diff --git a/.github/ISSUE_TEMPLATE/release.md b/.github/ISSUE_TEMPLATE/release.md new file mode 100644 index 0000000000..31321fddbd --- /dev/null +++ b/.github/ISSUE_TEMPLATE/release.md @@ -0,0 +1,156 @@ +--- +name: Release issue template +about: Tracking issue for new releases +title: Cumulus {{ env.VERSION }} Release checklist +--- +# Release Checklist + +### Runtime Releases + +These checks should be performed on the codebase. + +- [ ] Verify [`spec_version`](#spec-version) has been incremented since the + last release for any native runtimes from any existing use on public + (non-private/test) networks. +- [ ] Verify previously [completed migrations](#old-migrations-removed) are + removed for any public (non-private/test) networks. + - No migrations added in the last release that would need to be removed. +- [ ] Verify pallet and [extrinsic ordering](#extrinsic-ordering) as well as `SignedExtension`s have stayed + the same. Bump `transaction_version` if not. +- [ ] Verify new extrinsics have been correctly whitelisted/blacklisted for + [proxy filters](#proxy-filtering). + - No new extrinsics. +- [ ] Verify [benchmarks](#benchmarks) have been updated for any modified + runtime logic. + - [ ] Verify the weights are up-to-date. +- [ ] Verify that the various pieces of XCM config are sane. + +The following checks can be performed after we have forked off to the release- +candidate branch or started an additional release candidate branch (rc-2, rc-3, etc) + +- [ ] Verify [new migrations](#new-migrations) complete successfully, and the + runtime state is correctly updated for any public (non-private/test) + networks. +- [ ] Run integration tests. + - [ ] Teleport Relay -> Statemin* and back. + - [ ] Create asset (if applicable), mint and transfer +- [ ] Push runtime upgrade to Westmint and verify network stability. + + +### All Releases + +- [ ] Check that the new polkadot-collator versions have [run on the network](#burn-in) + without issue. +- [ ] Check that a draft release has been created at + https://github.com/paritytech/cumulus/releases with relevant [release + notes](#release-notes). +- [ ] Check that [build artifacts](#build-artifacts) have been added to the + draft-release. + +--- + +## Notes + +### Burn In + +Ensure that Parity DevOps has run the new release on Westmint and Statemine collators for 12h prior to publishing the release. + +### Build Artifacts + +Add any necessary assets to the release. They should include: + +- Linux binary +- GPG signature of the Linux binary +- SHA256 of binary +- Source code +- Wasm binaries of any runtimes + +### Release notes + +The release notes should list: + +- The priority of the release (i.e., how quickly users should upgrade) - this is + based on the max priority of any *client* changes. +- Which native runtimes and their versions are included +- The proposal hashes of the runtimes as built with + [srtool](https://github.com/paritytech/srtool) +- Any changes in this release that are still awaiting audit + +The release notes may also list: + +- Free text at the beginning of the notes mentioning anything important + regarding this release +- Notable changes separated into sections. + +### Spec Version + +A runtime upgrade must bump the spec number. This may follow a pattern with the +client release (e.g. runtime v12 corresponds to v0.8.12, even if the current +runtime is not v11). + +### Runtime version bump between RCs + +The clients need to be aware of runtime changes. However, we do not want to bump the +`spec_version` for every single release candidate. Instead, we can bump the `impl` field of the version +to signal the change to the client. + +### Old Migrations Removed + +Previous `on_runtime_upgrade` functions from old upgrades should be removed. + +### New Migrations + +Ensure that any migrations that are required due to storage or logic changes +are included in the `on_runtime_upgrade` function of the appropriate pallets. + +### Extrinsic Ordering & Storage + +Offline signing libraries depend on a consistent ordering of call indices and +functions. Compare the metadata of the current and new runtimes and ensure that +the `module index, call index` tuples map to the same set of functions. It also checks if there have been any changes in `storage`. In case of a breaking change, increase `transaction_version`. + +To verify the order has not changed, manually start the following [Github Action](https://github.com/paritytech/cumulus/actions/workflows/extrinsic-ordering-check-from-bin.yml). It takes around a minute to run and will produce the report as artifact you need to manually check. + +To run it, in the _Run Workflow_ dropdown: +1. **Use workflow from**: to ignore, leave `master` as default +2. **The WebSocket url of the reference node**: + - Statemine: `wss://kusama-statemine-rpc.paritytech.net` + - Westmint: `wss://westmint-rpc.polkadot.io` +3. **A url to a Linux binary for the node containing the runtime to test**: Paste the URL of the latest release-candidate binary from the draft-release on Github. The binary has to previously be uploaded to S3 (Github url link to the binary is constantly changing) + - https://releases.parity.io/cumulus/statemine-v6.0.0-rc1/polkadot-collator +4. **The name of the chain under test. Usually, you would pass a local chain**: + - Statemine: `statemine-local` + - Westmint: `westmint-local` +5. Click **Run workflow** + +When the workflow is done, click on it and download the zip artifact, inside you'll find an `output.txt` file. The things to look for in the output are lines like: + +- `[Identity] idx 28 -> 25 (calls 15)` - indicates the index for Identity has changed +- `[+] Society, Recovery` - indicates the new version includes 2 additional modules/pallets. +- If no indices have changed, every modules line should look something like `[Identity] idx 25 (calls 15)` + +**Note**: Adding new functions to the runtime does not constitute a breaking change +as long as the indexes did not change. + +**Note**: Extrinsic function signatures changes (adding/removing & ordering arguments) are not caught by the job, so those changes should be reviewed "manually" + +### Proxy Filtering + +The runtime contains proxy filters that map proxy types to allowable calls. If +the new runtime contains any new calls, verify that the proxy filters are up to +date to include them. + +### Benchmarks + +Until #631 is done, running the benchmarks is a manual process: +1. Connect to the bechmarking machine +2. Make sure no one else is using the machine with `htop check` +3. Pull in the branch of Cumulus that has the version of Statemine you want to release +4. Recompile `cargo build --release --features runtime-benchmarks` +5. From the root directory run `nohup ./scripts/benchmarks.sh &` (it will take quite a few hours) +6. Checkout in your local machine to the branch of cumulus that has the version of Statemine you want to release +7. `scp` from the host to your local machine the weights for Statemine, Westmint and Statemint you'll find in: + - `/polkadot-parachains/statemine/src/weights` + - `/polkadot-parachains/westmint/src/weights` + - `/polkadot-parachains/statemint/src/weights` +8. Commit the changes in your local and create a PR diff --git a/.github/workflows/check-labels.yml b/.github/workflows/check-labels.yml new file mode 100644 index 0000000000..f150054202 --- /dev/null +++ b/.github/workflows/check-labels.yml @@ -0,0 +1,23 @@ +name: Check labels + +on: + pull_request: + types: [labeled, opened, synchronize, unlabeled] + +jobs: + check-labels: + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v2 + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.ref }} + repository: ${{ github.event.pull_request.head.repo.full_name }} + - name: Check labels + run: bash ${{ github.workspace }}/scripts/github/check_labels.sh + env: + GITHUB_PR: ${{ github.event.pull_request.number }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + HEAD_SHA: ${{ github.event.pull_request.head.sha }} + BASE_SHA: ${{ github.event.pull_request.base.sha }} diff --git a/.github/workflows/release-01_rc-automation.yml b/.github/workflows/release-01_rc-automation.yml new file mode 100644 index 0000000000..138c950df3 --- /dev/null +++ b/.github/workflows/release-01_rc-automation.yml @@ -0,0 +1,63 @@ +name: Release-candidate automation +on: + push: + branches: + - release-**v[0-9]+.[0-9]+.[0-9]+ + workflow_dispatch: + +jobs: + tag_rc: + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v2 + with: + fetch-depth: 0 + - id: compute_tag + name: Compute next rc tag + shell: bash + run: | + # Get last rc tag if exists, else set it to {version}-rc1 + version=${GITHUB_REF#refs/heads/release-} + echo "$version" + echo "::set-output name=version::$version" + git tag -l + last_rc=$(git tag -l "$version-rc*" | sort -V | tail -n 1) + if [ -n "$last_rc" ]; then + suffix=$(echo "$last_rc" | grep -Eo '[0-9]+$') + echo $suffix + ((suffix++)) + echo $suffix + echo "::set-output name=new_tag::$version-rc$suffix" + echo "::set-output name=first_rc::false" + else + echo "::set-output name=new_tag::$version-rc1" + echo "::set-output name=first_rc::true" + fi + - name: Apply new tag + uses: tvdias/github-tagger@v0.0.2 + with: + # We can't use the normal GITHUB_TOKEN for the following reason: + # https://docs.github.com/en/actions/reference/events-that-trigger-workflows#triggering-new-workflows-using-a-personal-access-token + # RELEASE_BRANCH_TOKEN requires public_repo OAuth scope + repo-token: "${{ secrets.RELEASE_BRANCH_TOKEN }}" + tag: ${{ steps.compute_tag.outputs.new_tag }} + - id: create-issue + uses: JasonEtco/create-an-issue@v2 + # Only create the issue if it's the first release candidate + if: steps.compute_tag.outputs.first_rc == 'true' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + VERSION: ${{ steps.compute_tag.outputs.version }} + with: + filename: .github/ISSUE_TEMPLATE/release.md + - name: Send Matrix message + uses: s3krit/matrix-message-action@v0.0.3 + if: steps.create-issue.outputs.url != '' + with: + room_id: ${{ secrets.INTERNAL_CUMULUS_MATRIX_ROOM_ID }} + access_token: ${{ secrets.MATRIX_ACCESS_TOKEN }} + server: "matrix.parity.io" + message: | + Release process for Cumulus ${{ steps.compute_tag.outputs.version }} has been started. + Tracking issue: ${{ steps.create-issue.outputs.url }}" diff --git a/.github/workflows/release-02_create-draft.yml b/.github/workflows/release-02_create-draft.yml new file mode 100644 index 0000000000..cded2e1e5d --- /dev/null +++ b/.github/workflows/release-02_create-draft.yml @@ -0,0 +1,221 @@ +name: Release - Create draft + +on: + workflow_dispatch: + inputs: + ref1: + description: The 'from' tag to use for the diff + default: statemine-v5.0.0 + required: true + ref2: + description: The 'to' tag to use for the diff + default: release-statemine-v6 + required: true + pre_release: + description: For pre-releases + default: "true" + required: true + +jobs: + get-rust-versions: + runs-on: ubuntu-latest + container: + image: paritytech/ci-linux:production + outputs: + rustc-stable: ${{ steps.get-rust-versions.outputs.stable }} + rustc-nightly: ${{ steps.get-rust-versions.outputs.nightly }} + steps: + - id: get-rust-versions + run: | + echo "::set-output name=stable::$(rustc +stable --version)" + echo "::set-output name=nightly::$(rustc +nightly --version)" + + build-runtimes: + runs-on: ubuntu-latest + strategy: + matrix: + runtime: ["shell", "statemine", "statemint", "westmint", "rococo-parachain"] + steps: + - name: Checkout sources + uses: actions/checkout@v2 + with: + ref: ${{ github.event.inputs.ref2 }} + + - name: Cache target dir + uses: actions/cache@v2 + with: + path: "${{ github.workspace }}/runtime/${{ matrix.runtime }}/target" + key: srtool-target-${{ matrix.runtime }}-${{ github.sha }} + restore-keys: | + srtool-target-${{ matrix.runtime }}- + srtool-target- + + - name: Build ${{ matrix.runtime }} runtime + id: srtool_build + uses: chevdor/srtool-actions@v0.3.0 + with: + image: paritytech/srtool + chain: ${{ matrix.runtime }} + runtime_dir: polkadot-parachains/${{ matrix.runtime }} + + - name: Store srtool digest to disk + run: | + echo '${{ steps.srtool_build.outputs.json }}' | \ + jq > ${{ matrix.runtime }}_srtool_output.json + + - name: Upload ${{ matrix.runtime }} srtool json + uses: actions/upload-artifact@v2 + with: + name: ${{ matrix.runtime }}-srtool-json + path: ${{ matrix.runtime }}_srtool_output.json + + - name: Upload ${{ matrix.runtime }} runtime + uses: actions/upload-artifact@v2 + with: + name: ${{ matrix.runtime }}-runtime + path: | + ${{ steps.srtool_build.outputs.wasm_compressed }} + + publish-draft-release: + runs-on: ubuntu-latest + needs: ["get-rust-versions", "build-runtimes"] + outputs: + release_url: ${{ steps.create-release.outputs.html_url }} + asset_upload_url: ${{ steps.create-release.outputs.upload_url }} + steps: + - name: Checkout sources + uses: actions/checkout@v2 + with: + fetch-depth: 0 + path: cumulus + ref: ${{ github.event.inputs.ref2 }} + + - uses: ruby/setup-ruby@v1 + with: + ruby-version: 3.0.0 + + - name: Download srtool json output + uses: actions/download-artifact@v2 + + - name: Prepare tooling + run: | + cd cumulus/scripts/changelog + gem install bundler changelogerator + bundle install + changelogerator --help + + URL=https://github.com/chevdor/tera-cli/releases/download/v0.2.1/tera-cli_linux_amd64.deb + wget $URL -O tera.deb + sudo dpkg -i tera.deb + tera --version + + - name: Generate release notes + env: + RUSTC_STABLE: ${{ needs.get-rust-versions.outputs.rustc-stable }} + RUSTC_NIGHTLY: ${{ needs.get-rust-versions.outputs.rustc-nightly }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NO_CACHE: 1 + DEBUG: 1 + SHELL_DIGEST: ${{ github.workspace}}/shell-srtool-json/shell_srtool_output.json + WESTMINT_DIGEST: ${{ github.workspace}}/westmint-srtool-json/westmint_srtool_output.json + STATEMINE_DIGEST: ${{ github.workspace}}/statemine-srtool-json/statemine_srtool_output.json + STATEMINT_DIGEST: ${{ github.workspace}}/statemint-srtool-json/statemint_srtool_output.json + ROCOCO_DIGEST: ${{ github.workspace}}/rococo-parachain-srtool-json/rococo-parachain_srtool_output.json + REF1: ${{ github.event.inputs.ref1 }} + REF2: ${{ github.event.inputs.ref2 }} + PRE_RELEASE: ${{ github.event.inputs.pre_release }} + HIDE_SRTOOL_ROCOCO: false + HIDE_SRTOOL_SHELL: false + run: | + find ${{env.GITHUB_WORKSPACE}} -type f -name "*_srtool_output.json" + ls -al $SHELL_DIGEST + ls -al $WESTMINT_DIGEST + ls -al $STATEMINE_DIGEST + ls -al $STATEMINT_DIGEST + ls -al $ROCOCO_DIGEST + + echo "The diff will be computed from $REF1 to $REF2" + cd cumulus/scripts/changelog + ./bin/changelog $REF1 $REF2 release-notes.md + ls -al release-notes.md + ls -al context.json + + - name: Archive artifact context.json + uses: actions/upload-artifact@v2 + with: + name: release-notes-context + path: | + context.json + **/*_srtool_output.json + + - name: Create draft release + id: create-release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: parachains-${{ github.ref }} + release_name: Parachains ${{ github.ref }} + body_path: ./cumulus/scripts/changelog/release-notes.md + draft: true + + publish-runtimes: + runs-on: ubuntu-latest + needs: ["publish-draft-release"] + env: + RUNTIME_DIR: polkadot-parachains + strategy: + matrix: + runtime: ["shell", "statemine", "statemint", "westmint", "rococo-parachain"] + steps: + - name: Checkout sources + uses: actions/checkout@v2 + with: + ref: ${{ github.event.inputs.ref2 }} + + - name: Download artifacts + uses: actions/download-artifact@v2 + + - uses: ruby/setup-ruby@v1 + with: + ruby-version: 3.0.0 + + - name: Get runtime version for ${{ matrix.runtime }} + id: get-runtime-ver + run: | + echo "require './scripts/github/runtime-version.rb'" > script.rb + echo "puts get_runtime(runtime: \"${{ matrix.runtime }}\", runtime_dir: \"$RUNTIME_DIR\")" >> script.rb + + echo "Current folder: $PWD" + ls "$RUNTIME_DIR/${{ matrix.runtime }}" + runtime_ver=$(ruby script.rb) + echo "Found version: >$runtime_ver<" + echo "::set-output name=runtime_ver::$runtime_ver" + + - name: Upload compressed ${{ matrix.runtime }} wasm + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ needs.publish-draft-release.outputs.asset_upload_url }} + asset_path: "${{ matrix.runtime }}-runtime/${{ matrix.runtime }}_runtime.compact.compressed.wasm" + asset_name: ${{ matrix.runtime }}_runtime-v${{ steps.get-runtime-ver.outputs.runtime_ver }}.compact.compressed.wasm + asset_content_type: application/wasm + + post_to_matrix: + runs-on: ubuntu-latest + needs: publish-draft-release + steps: + - name: Internal polkadot channel + uses: s3krit/matrix-message-action@v0.0.3 + with: + room_id: ${{ secrets.INTERNAL_CUMULUS_MATRIX_ROOM_ID }} + access_token: ${{ secrets.MATRIX_ACCESS_TOKEN }} + message: | + **New draft for ${{ github.repository }}**: ${{ github.ref }}
+ + Draft release created: [draft](${{ needs.publish-draft-release.outputs.release_url }}) + + NOTE: The link above will no longer be valid if the draft is edited. You can then use the following link: + [${{ github.server_url }}/${{ github.repository }}/releases](${{ github.server_url }}/${{ github.repository }}/releases) + server: "matrix.parity.io" diff --git a/.github/workflows/release-10_docker.yml b/.github/workflows/release-10_docker.yml new file mode 100644 index 0000000000..b324a58af0 --- /dev/null +++ b/.github/workflows/release-10_docker.yml @@ -0,0 +1,121 @@ +name: Release - Docker + +# This workflow listens to pubished releases. +# It includes releases and pre-releases. +# It fetches the binaries, checks sha256 and GPG +# signatures, then builds an injected docker +# image and publishes it. + +on: + release: + types: + - published + +jobs: + docker_build_publish: + env: + BINARY: polkadot-collator + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v2 + with: + ref: ${{ github.event.release.tag_name }} + + - name: Fetch files from release + run: | + echo Repo: ${{ github.event.repository.full_name }} + + echo Name: ${{ github.event.release.name }} + echo Tag: ${{ github.event.release.tag_name }} + echo Draft: ${{ github.event.release.draft }} + echo Prerelease: ${{ github.event.release.prerelease }} + echo Assets: ${{ github.event.release.assets }} + + for f in $BINARY $BINARY.asc $BINARY.sha256; do + URL="https://github.com/${{ github.event.repository.full_name }}/releases/download/${{ github.event.release.tag_name }}/$f" + echo " - Fetching $f from $URL" + wget $URL -O $f + done + chmod a+x $BINARY + ls -al + + - name: Check files + run: | + ls -al *collator* + shasum -a 256 -c $BINARY.sha256 + sha_result=$? + + KEY_PARITY_SEC=9D4B2B6EB8F97156D19669A9FF0812D491B96798 + KEY_CHEVDOR=2835EAF92072BC01D188AF2C4A092B93E97CE1E2 + + gpg --receive-keys $KEY_PARITY_SEC + if [[ ${{ github.event.release.prerelease }} == "true" ]]; then + gpg --receive-keys $KEY_CHEVDOR + fi + + gpg --verify $BINARY.asc + gpg_result=$? + + echo sha_result: $sha_result + echo gpg_result: $gpg_result + + # If it fails, it would fail earlier but a second check + # does not hurt in case of refactoring... + if [[ $sha_result -ne 0 || $gpg_result -ne 0 ]]; then + echo "Check failed, exiting with error" + exit 1 + else + echo "Checks passed" + fi + + - name: Build injected image + env: + DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} + run: | + export OWNER=$DOCKERHUB_USERNAME + mkdir -p target/release + cp -f $BINARY* target/release/ + ./docker/scripts/build-injected-image.sh + + - name: Login to Dockerhub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Tag and Publish + env: + DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} + run: | + docker run --pull never --rm $DOCKERHUB_USERNAME/$BINARY --version + VERSION=$(docker run --pull never --rm $DOCKERHUB_USERNAME/$BINARY --version | awk '{ print $2 }' ) + SEMVER=$( echo $VERSION | cut -f1 -d- ) + GITREF=$( echo $VERSION | cut -f2 -d- ) + PRE=${{ github.event.release.prerelease }} + PRE_STR="" + + echo "SEMVER=$SEMVER" + echo "GITREF=$GITREF" + echo "PRE=$PRE" + + # Build a tag such as: + # 1.2.3-8a1201273 or + # 1.2.3-pre-8a1201273 for pre-releases + [[ $PRE == "true" ]] && PRE_STR="-pre" + TAG=${SEMVER}${PRE_STR}-${GITREF} + echo "PRE_STR=$PRE_STR" + echo "TAG=$TAG" + + docker tag $DOCKERHUB_USERNAME/$BINARY $DOCKERHUB_USERNAME/$BINARY:$TAG + docker push $DOCKERHUB_USERNAME/$BINARY:$TAG + + if [[ $PRE != "true" ]]; then + docker tag $DOCKERHUB_USERNAME/$BINARY $DOCKERHUB_USERNAME/$BINARY:latest + docker tag $DOCKERHUB_USERNAME/$BINARY $DOCKERHUB_USERNAME/$BINARY:$SEMVER + + docker push $DOCKERHUB_USERNAME/$BINARY:latest + docker push $DOCKERHUB_USERNAME/$BINARY:$SEMVER + fi + + docker images | grep $DOCKERHUB_USERNAME/$BINARY diff --git a/.github/workflows/release-bot.yml b/.github/workflows/release-99_bot-announce.yml similarity index 92% rename from .github/workflows/release-bot.yml rename to .github/workflows/release-99_bot-announce.yml index 29979e41e4..e020acfdc8 100644 --- a/.github/workflows/release-bot.yml +++ b/.github/workflows/release-99_bot-announce.yml @@ -1,4 +1,4 @@ -name: Pushes release notes to a Matrix room +name: Release - Pushes release notes to a Matrix room on: release: types: diff --git a/.github/workflows/srtool.yml b/.github/workflows/srtool.yml index e1a615250a..69b68c779b 100644 --- a/.github/workflows/srtool.yml +++ b/.github/workflows/srtool.yml @@ -1,7 +1,7 @@ name: Srtool build env: - SUBWASM_VERSION: 0.14.1 + SUBWASM_VERSION: 0.15.0 on: push: @@ -14,6 +14,10 @@ on: - "scripts" - "test" + branches: + - "release*" + - "master" + schedule: - cron: "00 02 * * 1" # 2AM weekly on monday @@ -24,7 +28,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - chain: ["statemine", "westmint", "statemint", "rococo", "shell"] + chain: ["statemine", "westmint", "statemint", "rococo-parachain", "shell"] steps: - uses: actions/checkout@v2 with: diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5b7a9c85c5..4df23018a0 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -107,6 +107,29 @@ test-linux-stable: fi - sccache -s +check-runtime-benchmarks: + stage: test + <<: *docker-env + script: + # Check that the node will compile with `runtime-benchmarks` feature flag. + - time cargo check --all --features runtime-benchmarks + - sccache -s + +cargo-check-try-runtime: + stage: test + <<: *docker-env + script: + # Check that the node will compile with `try-runtime` feature flag. + - time cargo check --all --features try-runtime + - sccache -s + +cargo-check-benches: + stage: test + <<: *docker-env + script: + - time cargo check --all --benches + - sccache -s + #### stage: publish publish-s3: diff --git a/.rustfmt.toml b/.rustfmt.toml index 3018614bb1..bfa2448ee1 100644 --- a/.rustfmt.toml +++ b/.rustfmt.toml @@ -1,4 +1,5 @@ # Basic +edition = "2021" hard_tabs = true max_width = 100 use_small_heuristics = "Max" diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 0000000000..3810c3101c --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1,27 @@ +# Lists some code owners. +# +# A codeowner just oversees some part of the codebase. If an owned file is changed then the +# corresponding codeowner receives a review request. An approval of the codeowner might be +# required for merging a PR (depends on repository settings). +# +# For details about syntax, see: +# https://help.github.com/en/articles/about-code-owners +# But here are some important notes: +# +# - Glob syntax is git-like, e.g. `/core` means the core directory in the root, unlike `core` +# which can be everywhere. +# - Multiple owners are supported. +# - Either handle (e.g, @github_user or @github/team) or email can be used. Keep in mind, +# that handles might work better because they are more recognizable on GitHub, +# eyou can use them for mentioning unlike an email. +# - The latest matching rule, if multiple, takes precedence. + +# CI +/.github/ @paritytech/ci @chevdor +/.gitlab-ci.yml @paritytech/ci +/scripts/ci/ @paritytech/ci +/scripts/github/ @paritytech/ci @chevdor +/scripts/extrinsic-ordering-filter.sh @paritytech/ci @chevdor + +# CHANGELOG +/scripts/changelog/ @chevdor diff --git a/Cargo.lock b/Cargo.lock index bbf74a6884..54a9e6c8d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18,57 +18,66 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e61f2b7f93d2c7d2b08263acaa4a363b3e276806c68af6134c44f523bf1aacd" dependencies = [ - "gimli", + "gimli 0.25.0", +] + +[[package]] +name = "addr2line" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" +dependencies = [ + "gimli 0.26.1", ] [[package]] name = "adler" -version = "0.2.3" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aead" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e3e798aa0c8239776f54415bc06f3d74b1850f3f830b45c35cfc80556973f70" +checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877" dependencies = [ "generic-array 0.14.4", ] [[package]] name = "aes" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "495ee669413bfbe9e8cace80f4d3d78e6d8c8d99579f97fb93bde351b185f2d4" +checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" dependencies = [ "cfg-if 1.0.0", "cipher", - "cpufeatures 0.1.5", + "cpufeatures 0.2.1", "opaque-debug 0.3.0", ] [[package]] name = "aes-gcm" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2a930fd487faaa92a30afa92cc9dd1526a5cff67124abbbb1c617ce070f4dcf" +checksum = "df5f85a83a7d8b0442b6aa7b504b8212c1733da07b98aae43d4bc21b2cb3cdf6" dependencies = [ "aead", "aes", "cipher", "ctr", "ghash", - "subtle 2.4.0", + "subtle", ] [[package]] name = "ahash" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43bb833f0bf979d8475d38fbf09ed3b8a55e1885fe93ad3f93239fc6a4f17b98" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" dependencies = [ - "getrandom 0.2.1", + "getrandom 0.2.3", "once_cell", "version_check", ] @@ -88,15 +97,6 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbf688625d06217d5b1bb0ea9d9c44a1635fd0ee3534466388d18203174f4d11" -[[package]] -name = "ansi_term" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" -dependencies = [ - "winapi 0.3.9", -] - [[package]] name = "ansi_term" version = "0.12.1" @@ -108,9 +108,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.40" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b" +checksum = "8b26702f315f53b6071259e15dd9d64528213b44d61de1ec926eca7715d62203" [[package]] name = "approx" @@ -144,9 +144,9 @@ checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" [[package]] name = "arrayvec" -version = "0.7.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a2f58b0bb10c380af2b26e57212856b8c9a59e0925b4c20f4a174a49734eaf7" +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" [[package]] name = "asn1_der" @@ -186,9 +186,9 @@ dependencies = [ [[package]] name = "async-channel" -version = "1.5.1" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59740d83946db6a5af71ae25ddf9562c2b176b2ca42cf99a455f09f4a220d6b9" +checksum = "2114d64672151c0c5eaa5e131ec84a74f06e1e559830dabba01ca30605d66319" dependencies = [ "concurrent-queue", "event-listener", @@ -197,16 +197,16 @@ dependencies = [ [[package]] name = "async-executor" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb877970c7b440ead138f6321a3b5395d6061183af779340b65e20c0fede9146" +checksum = "871f9bb5e0a22eeb7e8cf16641feb87c9dc67032ccf8ff49e772eb9941d3a965" dependencies = [ "async-task", "concurrent-queue", "fastrand", "futures-lite", "once_cell", - "vec-arena", + "slab", ] [[package]] @@ -227,20 +227,19 @@ dependencies = [ [[package]] name = "async-io" -version = "1.3.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9315f8f07556761c3e48fec2e6b276004acf426e6dc068b2c2251854d65ee0fd" +checksum = "a811e6a479f2439f0c04038796b5cfb3d2ad56c230e0f2d3f7b04d68cfee607b" dependencies = [ "concurrent-queue", - "fastrand", "futures-lite", "libc", "log", - "nb-connect", "once_cell", "parking", "polling", - "vec-arena", + "slab", + "socket2 0.4.2", "waker-fn", "winapi 0.3.9", ] @@ -265,9 +264,9 @@ dependencies = [ [[package]] name = "async-process" -version = "1.1.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f38756dd9ac84671c428afbf7c9f7495feff9ec5b0710f17100098e5b354ac" +checksum = "83137067e3a2a6a06d67168e49e68a0957d215410473a740cea95a2425c0b7c6" dependencies = [ "async-io", "blocking", @@ -303,7 +302,7 @@ dependencies = [ "memchr", "num_cpus", "once_cell", - "pin-project-lite 0.2.4", + "pin-project-lite 0.2.7", "pin-utils", "slab", "wasm-bindgen-futures", @@ -311,9 +310,9 @@ dependencies = [ [[package]] name = "async-std-resolver" -version = "0.20.1" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665c56111e244fe38e7708ee10948a4356ad6a548997c21f5a63a0f4e0edc4d" +checksum = "ed4e2c3da14d8ad45acb1e3191db7a918e9505b6f155b218e70a7c9a1a48c638" dependencies = [ "async-std", "async-trait", @@ -331,9 +330,9 @@ checksum = "e91831deabf0d6d7ec49552e489aed63b7456a7a3c46cff62adad428110b0af0" [[package]] name = "async-trait" -version = "0.1.51" +version = "0.1.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44318e776df68115a881de9a8fd1b9e53368d7a4a5ce4cc48517da3393233a5e" +checksum = "061a7acccaa286c011ddc30970520b98fa40e00c9d644633fb26b5fc63a265e3" dependencies = [ "proc-macro2", "quote", @@ -346,11 +345,11 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb4401f0a3622dad2e0763fa79e0eb328bc70fb7dccfdd645341f00d671247d6" dependencies = [ - "bytes 1.0.1", + "bytes 1.1.0", "futures-sink", "futures-util", "memchr", - "pin-project-lite 0.2.4", + "pin-project-lite 0.2.7", ] [[package]] @@ -359,18 +358,18 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0de5164e5edbf51c45fb8c2d9664ae1c095cce1b265ecf7569093c0d66ef690" dependencies = [ - "bytes 1.0.1", + "bytes 1.1.0", "futures-sink", "futures-util", "memchr", - "pin-project-lite 0.2.4", + "pin-project-lite 0.2.7", ] [[package]] name = "atomic" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3410529e8288c463bedb5930f82833bc0c90e5d2fe639a56582a4d09220b281" +checksum = "b88d82667eca772c4aa12f0f1348b3ae643424c8876448f3f7bd5787032e234c" dependencies = [ "autocfg", ] @@ -400,11 +399,11 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "backtrace" -version = "0.3.61" +version = "0.3.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7a905d892734eea339e896738c14b9afce22b5318f64b951e70bf3844419b01" +checksum = "321629d8ba6513061f26707241fa9bc89524ff1cd7a915a97ef0c62c666ce1b6" dependencies = [ - "addr2line", + "addr2line 0.17.0", "cc", "cfg-if 1.0.0", "libc", @@ -413,19 +412,6 @@ dependencies = [ "rustc-demangle", ] -[[package]] -name = "bae" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec107f431ee3d8a8e45e6dd117adab769556ef463959e77bf6a4888d5fd500cf" -dependencies = [ - "heck", - "proc-macro-error 0.4.12", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "base-x" version = "0.2.8" @@ -438,12 +424,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6107fe1be6682a68940da878d9e9f5e90ca5745b3dec9fd1bb393c8777d4f581" -[[package]] -name = "base64" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" - [[package]] name = "base64" version = "0.13.0" @@ -452,9 +432,9 @@ checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" [[package]] name = "beef" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6736e2428df2ca2848d846c43e88745121a6654696e349ce0054a420815a7409" +checksum = "bed554bd50246729a1ec158d08aa3235d1b69d94ad120ebe187e28894787e736" dependencies = [ "serde", ] @@ -462,14 +442,14 @@ dependencies = [ [[package]] name = "beefy-gadget" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "beefy-primitives", "fnv", - "futures 0.3.17", + "futures 0.3.19", "log", "parity-scale-codec", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "sc-client-api", "sc-keystore", "sc-network", @@ -490,11 +470,11 @@ dependencies = [ [[package]] name = "beefy-gadget-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "beefy-gadget", "beefy-primitives", - "futures 0.3.17", + "futures 0.3.19", "jsonrpc-core", "jsonrpc-core-client", "jsonrpc-derive", @@ -510,12 +490,12 @@ dependencies = [ [[package]] name = "beefy-merkle-tree" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" [[package]] name = "beefy-primitives" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "parity-scale-codec", "scale-info", @@ -527,20 +507,25 @@ dependencies = [ ] [[package]] -name = "bincode" -version = "1.3.1" +name = "bimap" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30d3a39baa26f9651f17b375061f3233dde33424a8b72b0dbe93a68a0bc896d" +checksum = "50ae17cabbc8a38a1e3e4c1a6a664e9a09672dc14d0896fa8d865d3a5a446b07" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" dependencies = [ - "byteorder", "serde", ] [[package]] name = "bindgen" -version = "0.59.1" +version = "0.59.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453c49e5950bb0eb63bb3df640e31618846c89d5b7faa54040d76e98e0134375" +checksum = "2bd2a9a458e8f4304c52c43ebb0cfbd520289f8379a52e329a38afda99bf8eb8" dependencies = [ "bitflags", "cexpr", @@ -563,33 +548,21 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitvec" -version = "0.19.5" +version = "0.20.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8942c8d352ae1838c9dda0b0ca2ab657696ef2232a20147cf1b30ae1a9cb4321" +checksum = "7774144344a4faa177370406a7ff5f1da24303817368584c6206c8303eb07848" dependencies = [ "funty", - "radium 0.5.3", - "tap", - "wyz", -] - -[[package]] -name = "bitvec" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5011ffc90248764d7005b0e10c7294f5aa1bd87d9dd7248f4ad475b347c294d" -dependencies = [ - "funty", - "radium 0.6.2", + "radium", "tap", "wyz", ] [[package]] name = "blake2" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a5720225ef5daecf08657f23791354e1685a8c91a4c60c7f3d3b2892f978f4" +checksum = "0a4e37d16930f5459780f5621038b6382b9bb37c19016f39fb6b5808d831f174" dependencies = [ "crypto-mac 0.8.0", "digest 0.9.0", @@ -630,9 +603,9 @@ dependencies = [ [[package]] name = "blake3" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9ff35b701f3914bdb8fad3368d822c766ef2858b2583198e41639b936f09d3f" +checksum = "b64485778c4f16a6a5a9d335e80d449ac6c70cdd6a06d2af18a6f6f775a125b3" dependencies = [ "arrayref", "arrayvec 0.5.2", @@ -652,7 +625,7 @@ dependencies = [ "block-padding 0.1.5", "byte-tools", "byteorder", - "generic-array 0.12.3", + "generic-array 0.12.4", ] [[package]] @@ -682,9 +655,9 @@ checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" [[package]] name = "blocking" -version = "1.0.2" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e170dbede1f740736619b776d7251cb1b9095c435c34d8ca9f57fcd2f335e9" +checksum = "046e47d4b2d391b1f6f8b407b1deb8dee56c1852ccd868becf2710f601b5f427" dependencies = [ "async-channel", "async-task", @@ -696,9 +669,9 @@ dependencies = [ [[package]] name = "bounded-vec" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afdd1dffefe5fc66262a524b91087c43b16e478b2e3dc49eb11b0e2fd6b6ec90" +checksum = "b47cca82fca99417fe405f09d93bb8fff90bdd03d13c631f18096ee123b4281c" dependencies = [ "thiserror", ] @@ -706,7 +679,7 @@ dependencies = [ [[package]] name = "bp-header-chain" version = "0.1.0" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "finality-grandpa", "frame-support", @@ -722,7 +695,7 @@ dependencies = [ [[package]] name = "bp-message-dispatch" version = "0.1.0" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "bp-runtime", "frame-support", @@ -734,9 +707,9 @@ dependencies = [ [[package]] name = "bp-messages" version = "0.1.0" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ - "bitvec 0.20.1", + "bitvec", "bp-runtime", "frame-support", "frame-system", @@ -750,7 +723,7 @@ dependencies = [ [[package]] name = "bp-polkadot-core" version = "0.1.0" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "bp-messages", "bp-runtime", @@ -765,25 +738,10 @@ dependencies = [ "sp-version", ] -[[package]] -name = "bp-rialto" -version = "0.1.0" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" -dependencies = [ - "bp-messages", - "bp-runtime", - "frame-support", - "frame-system", - "sp-api", - "sp-core", - "sp-runtime", - "sp-std", -] - [[package]] name = "bp-rococo" version = "0.1.0" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "bp-messages", "bp-polkadot-core", @@ -800,7 +758,7 @@ dependencies = [ [[package]] name = "bp-runtime" version = "0.1.0" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "frame-support", "hash-db", @@ -818,7 +776,7 @@ dependencies = [ [[package]] name = "bp-test-utils" version = "0.1.0" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "bp-header-chain", "ed25519-dalek", @@ -833,7 +791,7 @@ dependencies = [ [[package]] name = "bp-wococo" version = "0.1.0" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "bp-messages", "bp-polkadot-core", @@ -848,7 +806,7 @@ dependencies = [ [[package]] name = "bridge-runtime-common" version = "0.1.0" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "bp-message-dispatch", "bp-messages", @@ -876,11 +834,14 @@ checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" [[package]] name = "bstr" -version = "0.2.14" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "473fc6b38233f9af7baa94fb5852dca389e3d95b8e21c8e3719301462c5d9faf" +checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" dependencies = [ + "lazy_static", "memchr", + "regex-automata", + "serde", ] [[package]] @@ -894,15 +855,15 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.4.0" +version = "3.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820" +checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c" [[package]] name = "byte-slice-cast" -version = "1.0.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65c1bf4a04a88c54f589125563643d773f3254b5c38571395e2b591c693bbc81" +checksum = "1d30c751592b77c499e7bce34d99d67c2c11bdc0574e9a488ddade14150a4698" [[package]] name = "byte-tools" @@ -912,9 +873,9 @@ checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" [[package]] name = "byteorder" -version = "1.3.4" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" @@ -928,15 +889,9 @@ dependencies = [ [[package]] name = "bytes" -version = "0.5.6" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" - -[[package]] -name = "bytes" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" [[package]] name = "cache-padded" @@ -946,50 +901,58 @@ checksum = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba" [[package]] name = "camino" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4648c6d00a709aa069a236adcaae4f605a6241c72bf5bee79331a4b625921a9" +checksum = "52d74260d9bf6944e2208aa46841b4b8f0d7ffc0849a06837b2f510337f86b2b" dependencies = [ "serde", ] [[package]] name = "cargo-platform" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0226944a63d1bf35a3b5f948dd7c59e263db83695c9e8bffc4037de02e30f1d7" +checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27" dependencies = [ "serde", ] [[package]] name = "cargo_metadata" -version = "0.13.1" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "081e3f0755c1f380c2d010481b6fa2e02973586d5f2b24eebb7a2a1d98b143d8" +checksum = "ba2ae6de944143141f6155a473a6b02f66c7c3f9f47316f802f80204ebfe6e12" dependencies = [ "camino", "cargo-platform", - "semver 0.11.0", - "semver-parser 0.10.2", + "semver 1.0.4", "serde", "serde_json", ] [[package]] -name = "cc" -version = "1.0.71" +name = "cast" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79c2681d6594606957bbb8631c4b90a7fcaaa72cdb714743a437b156d6a7eedd" +checksum = "4c24dab4283a142afa2fdca129b80ad2c6284e073930f964c3a1293c225ee39a" +dependencies = [ + "rustc_version 0.4.0", +] + +[[package]] +name = "cc" +version = "1.0.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" dependencies = [ "jobserver", ] [[package]] name = "cexpr" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db507a7679252d2276ed0dd8113c6875ec56d3089f9225b2b42c30cc1f8e5c89" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" dependencies = [ "nom", ] @@ -1052,9 +1015,9 @@ dependencies = [ [[package]] name = "cid" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d88f30b1e74e7063df5711496f3ee6e74a9735d62062242d70cddf77717f18e" +checksum = "ff0e3bc0b6446b3f9663c1a6aba6ef06c5aeaa1bc92bd18077be337198ab9768" dependencies = [ "multibase", "multihash 0.13.2", @@ -1072,31 +1035,31 @@ dependencies = [ [[package]] name = "ckb-merkle-mountain-range" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e486fe53bb9f2ca0f58cb60e8679a5354fd6687a839942ef0a75967250289ca6" +checksum = "4f061f97d64fd1822664bdfb722f7ae5469a97b77567390f7442be5b5dc82a5b" dependencies = [ "cfg-if 0.1.10", ] [[package]] name = "clang-sys" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "853eda514c284c2287f4bf20ae614f8781f40a81d32ecda6e91449304dfe077c" +checksum = "fa66045b9cb23c2e9c1520732030608b02ee07e5cfaa5a521ec15ded7fa24c90" dependencies = [ "glob", "libc", - "libloading 0.7.0", + "libloading 0.7.2", ] [[package]] name = "clap" -version = "2.33.3" +version = "2.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" dependencies = [ - "ansi_term 0.11.0", + "ansi_term", "atty", "bitflags", "strsim", @@ -1123,12 +1086,6 @@ dependencies = [ "cache-padded", ] -[[package]] -name = "const_fn" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd51eab21ab4fd6a3bf889e2d0958c0a6e3a61ad04260325e919e652a2a62826" - [[package]] name = "constant_time_eq" version = "0.1.5" @@ -1143,9 +1100,9 @@ checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" [[package]] name = "core-foundation" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a89e2ae426ea83155dccf10c0fa6b1463ef6d5fcb44cee0b224a408fa640a62" +checksum = "6888e10551bb93e424d8df1d07f1a8b4fceb0001a3a4b048bfc47554946f47b3" dependencies = [ "core-foundation-sys", "libc", @@ -1153,18 +1110,17 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" [[package]] name = "cpp_demangle" -version = "0.3.2" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44919ecaf6f99e8e737bc239408931c9a01e9a6c74814fee8242dd2506b65390" +checksum = "eeaa953eaad386a53111e47172c2fedba671e5684c8dd601a5f474f4f118710f" dependencies = [ "cfg-if 1.0.0", - "glob", ] [[package]] @@ -1185,32 +1141,26 @@ dependencies = [ "libc", ] -[[package]] -name = "cpuid-bool" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634" - [[package]] name = "cranelift-bforest" -version = "0.77.0" +version = "0.78.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15013642ddda44eebcf61365b2052a23fd8b7314f90ba44aa059ec02643c5139" +checksum = "cc0cb7df82c8cf8f2e6a8dd394a0932a71369c160cc9b027dca414fced242513" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-codegen" -version = "0.77.0" +version = "0.78.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "298f2a7ed5fdcb062d8e78b7496b0f4b95265d20245f2d0ca88f846dd192a3a3" +checksum = "fe4463c15fa42eee909e61e5eac4866b7c6d22d0d8c621e57a0c5380753bfa8c" dependencies = [ "cranelift-bforest", "cranelift-codegen-meta", "cranelift-codegen-shared", "cranelift-entity", - "gimli", + "gimli 0.25.0", "log", "regalloc", "smallvec", @@ -1219,9 +1169,9 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.77.0" +version = "0.78.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cf504261ac62dfaf4ffb3f41d88fd885e81aba947c1241275043885bc5f0bac" +checksum = "793f6a94a053a55404ea16e1700202a88101672b8cd6b4df63e13cde950852bf" dependencies = [ "cranelift-codegen-shared", "cranelift-entity", @@ -1229,24 +1179,24 @@ dependencies = [ [[package]] name = "cranelift-codegen-shared" -version = "0.77.0" +version = "0.78.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd2a72db4301dbe7e5a4499035eedc1e82720009fb60603e20504d8691fa9cd" +checksum = "44aa1846df275bce5eb30379d65964c7afc63c05a117076e62a119c25fe174be" [[package]] name = "cranelift-entity" -version = "0.77.0" +version = "0.78.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48868faa07cacf948dc4a1773648813c0e453ff9467e800ff10f6a78c021b546" +checksum = "a3a45d8d6318bf8fc518154d9298eab2a8154ec068a8885ff113f6db8d69bb3a" dependencies = [ "serde", ] [[package]] name = "cranelift-frontend" -version = "0.77.0" +version = "0.78.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "351c9d13b4ecd1a536215ec2fd1c3ee9ee8bc31af172abf1e45ed0adb7a931df" +checksum = "e07339bd461766deb7605169de039e01954768ff730fa1254e149001884a8525" dependencies = [ "cranelift-codegen", "log", @@ -1256,9 +1206,9 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.77.0" +version = "0.78.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6df8b556663d7611b137b24db7f6c8d9a8a27d7f29c7ea7835795152c94c1b75" +checksum = "03e2fca76ff57e0532936a71e3fc267eae6a19a86656716479c66e7f912e3d7b" dependencies = [ "cranelift-codegen", "libc", @@ -1267,9 +1217,9 @@ dependencies = [ [[package]] name = "cranelift-wasm" -version = "0.77.0" +version = "0.78.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a69816d90db694fa79aa39b89dda7208a4ac74b6f2b8f3c4da26ee1c8bdfc5e" +checksum = "1f46fec547a1f8a32c54ea61c28be4f4ad234ad95342b718a9a9adcaadb0c778" dependencies = [ "cranelift-codegen", "cranelift-entity", @@ -1283,18 +1233,56 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.2.1" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" +checksum = "738c290dfaea84fc1ca15ad9c168d083b05a714e1efddd8edaab678dc28d2836" dependencies = [ "cfg-if 1.0.0", ] [[package]] -name = "crossbeam-channel" -version = "0.5.0" +name = "criterion" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775" +checksum = "1604dafd25fba2fe2d5895a9da139f8dc9b319a5fe5354ca137cbbce4e178d10" +dependencies = [ + "atty", + "cast", + "clap", + "criterion-plot", + "csv", + "futures 0.3.19", + "itertools", + "lazy_static", + "num-traits", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_cbor", + "serde_derive", + "serde_json", + "tinytemplate", + "tokio", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d00996de9f2f7559f7f4dc286073197f83e92256a59ed395f9aac01fe717da57" +dependencies = [ + "cast", + "itertools", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" dependencies = [ "cfg-if 1.0.0", "crossbeam-utils", @@ -1302,9 +1290,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9" +checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" dependencies = [ "cfg-if 1.0.0", "crossbeam-epoch", @@ -1313,12 +1301,11 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.1" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1aaa739f95311c2c7887a76863f500026092fb1dce0161dab577e559ef3569d" +checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd" dependencies = [ "cfg-if 1.0.0", - "const_fn", "crossbeam-utils", "lazy_static", "memoffset", @@ -1327,11 +1314,10 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.1" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d" +checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" dependencies = [ - "autocfg", "cfg-if 1.0.0", "lazy_static", ] @@ -1342,16 +1328,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" -[[package]] -name = "crypto-mac" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5" -dependencies = [ - "generic-array 0.12.3", - "subtle 1.0.0", -] - [[package]] name = "crypto-mac" version = "0.8.0" @@ -1359,7 +1335,39 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" dependencies = [ "generic-array 0.14.4", - "subtle 2.4.0", + "subtle", +] + +[[package]] +name = "crypto-mac" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" +dependencies = [ + "generic-array 0.14.4", + "subtle", +] + +[[package]] +name = "csv" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" +dependencies = [ + "bstr", + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" +dependencies = [ + "memchr", ] [[package]] @@ -1373,9 +1381,9 @@ dependencies = [ [[package]] name = "ctor" -version = "0.1.19" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8f45d9ad417bcef4817d614a501ab55cdd96a6fdb24f49aab89a54acfd66b19" +checksum = "ccc0a48a9b826acdf4028595adc9db92caea352f7af011a3034acd172a52a0aa" dependencies = [ "quote", "syn", @@ -1418,9 +1426,10 @@ dependencies = [ "cumulus-client-consensus-common", "cumulus-client-network", "cumulus-primitives-core", + "cumulus-relay-chain-interface", "cumulus-test-client", "cumulus-test-runtime", - "futures 0.3.17", + "futures 0.3.19", "parity-scale-codec", "parking_lot 0.10.2", "polkadot-node-primitives", @@ -1445,9 +1454,8 @@ dependencies = [ "async-trait", "cumulus-client-consensus-common", "cumulus-primitives-core", - "futures 0.3.17", + "futures 0.3.19", "parity-scale-codec", - "polkadot-client", "sc-client-api", "sc-consensus", "sc-consensus-aura", @@ -1472,9 +1480,10 @@ name = "cumulus-client-consensus-common" version = "0.1.0" dependencies = [ "async-trait", + "cumulus-relay-chain-interface", "cumulus-test-client", "dyn-clone", - "futures 0.3.17", + "futures 0.3.19", "futures-timer 3.0.2", "parity-scale-codec", "polkadot-primitives", @@ -1496,9 +1505,9 @@ dependencies = [ "async-trait", "cumulus-client-consensus-common", "cumulus-primitives-core", - "futures 0.3.17", + "cumulus-relay-chain-interface", + "futures 0.3.19", "parking_lot 0.10.2", - "polkadot-client", "sc-client-api", "sc-consensus", "sp-api", @@ -1516,17 +1525,21 @@ dependencies = [ name = "cumulus-client-network" version = "0.1.0" dependencies = [ + "async-trait", "cumulus-primitives-core", + "cumulus-relay-chain-interface", + "cumulus-relay-chain-local", "cumulus-test-service", "derive_more", - "futures 0.3.17", + "futures 0.3.19", "futures-timer 3.0.2", "parity-scale-codec", - "parking_lot 0.10.2", + "parking_lot 0.11.2", "polkadot-client", "polkadot-node-primitives", "polkadot-parachain", "polkadot-primitives", + "polkadot-service", "polkadot-test-client", "sc-cli", "sc-client-api", @@ -1538,6 +1551,7 @@ dependencies = [ "sp-keyring", "sp-keystore", "sp-runtime", + "sp-state-machine", "substrate-test-utils", "tokio", "tracing", @@ -1548,8 +1562,9 @@ name = "cumulus-client-pov-recovery" version = "0.1.0" dependencies = [ "cumulus-primitives-core", + "cumulus-relay-chain-interface", "cumulus-test-service", - "futures 0.3.17", + "futures 0.3.19", "futures-timer 3.0.2", "parity-scale-codec", "polkadot-node-primitives", @@ -1578,11 +1593,11 @@ dependencies = [ "cumulus-client-consensus-common", "cumulus-client-pov-recovery", "cumulus-primitives-core", + "cumulus-relay-chain-interface", "parity-scale-codec", "parking_lot 0.10.2", "polkadot-overseer", "polkadot-primitives", - "polkadot-service", "sc-chain-spec", "sc-client-api", "sc-consensus", @@ -1688,6 +1703,7 @@ dependencies = [ "frame-support", "frame-system", "pallet-session", + "parity-scale-codec", "sp-runtime", "sp-std", ] @@ -1768,9 +1784,9 @@ version = "0.1.0" dependencies = [ "async-trait", "cumulus-primitives-core", + "cumulus-relay-chain-interface", "cumulus-test-relay-sproof-builder", "parity-scale-codec", - "polkadot-client", "sc-client-api", "scale-info", "sp-api", @@ -1779,6 +1795,7 @@ dependencies = [ "sp-runtime", "sp-state-machine", "sp-std", + "sp-storage", "sp-trie", "tracing", ] @@ -1790,7 +1807,7 @@ dependencies = [ "cumulus-primitives-core", "cumulus-test-client", "cumulus-test-relay-sproof-builder", - "futures 0.3.17", + "futures 0.3.19", "parity-scale-codec", "sp-consensus", "sp-inherents", @@ -1816,6 +1833,54 @@ dependencies = [ "xcm", ] +[[package]] +name = "cumulus-relay-chain-interface" +version = "0.1.0" +dependencies = [ + "async-trait", + "cumulus-primitives-core", + "derive_more", + "parking_lot 0.11.2", + "polkadot-overseer", + "sc-client-api", + "sp-api", + "sp-blockchain", + "sp-core", + "sp-runtime", + "sp-state-machine", +] + +[[package]] +name = "cumulus-relay-chain-local" +version = "0.1.0" +dependencies = [ + "async-trait", + "cumulus-primitives-core", + "cumulus-relay-chain-interface", + "cumulus-test-service", + "futures 0.3.19", + "futures-timer 3.0.2", + "parking_lot 0.11.2", + "polkadot-client", + "polkadot-primitives", + "polkadot-service", + "polkadot-test-client", + "sc-client-api", + "sc-consensus-babe", + "sc-network", + "sc-service", + "sc-telemetry", + "sc-tracing", + "sp-api", + "sp-blockchain", + "sp-consensus", + "sp-core", + "sp-keyring", + "sp-runtime", + "sp-state-machine", + "tracing", +] + [[package]] name = "cumulus-test-client" version = "0.1.0" @@ -1876,40 +1941,8 @@ dependencies = [ "frame-executive", "frame-support", "frame-system", + "frame-system-rpc-runtime-api", "pallet-balances", - "pallet-randomness-collective-flip", - "pallet-sudo", - "pallet-timestamp", - "pallet-transaction-payment", - "parity-scale-codec", - "scale-info", - "serde", - "sp-api", - "sp-block-builder", - "sp-core", - "sp-inherents", - "sp-io", - "sp-offchain", - "sp-runtime", - "sp-session", - "sp-std", - "sp-transaction-pool", - "sp-version", - "substrate-wasm-builder", -] - -[[package]] -name = "cumulus-test-runtime-upgrade" -version = "0.1.0" -dependencies = [ - "cumulus-pallet-parachain-system", - "cumulus-primitives-core", - "cumulus-primitives-timestamp", - "frame-executive", - "frame-support", - "frame-system", - "pallet-balances", - "pallet-randomness-collective-flip", "pallet-sudo", "pallet-timestamp", "pallet-transaction-payment", @@ -1935,20 +1968,23 @@ name = "cumulus-test-service" version = "0.1.0" dependencies = [ "async-trait", + "criterion", "cumulus-client-consensus-common", "cumulus-client-consensus-relay-chain", "cumulus-client-network", "cumulus-client-service", "cumulus-primitives-core", "cumulus-primitives-parachain-inherent", + "cumulus-relay-chain-local", "cumulus-test-relay-validation-worker-provider", "cumulus-test-runtime", - "cumulus-test-runtime-upgrade", "frame-system", - "futures 0.3.17", + "frame-system-rpc-runtime-api", + "futures 0.3.19", "jsonrpc-core", "pallet-transaction-payment", "parity-scale-codec", + "parking_lot 0.11.2", "polkadot-primitives", "polkadot-service", "polkadot-test-service", @@ -1964,17 +2000,18 @@ dependencies = [ "sc-service", "sc-tracing", "sc-transaction-pool", + "sc-transaction-pool-api", "serde", "sp-arithmetic", "sp-blockchain", "sp-core", + "sp-io", "sp-keyring", - "sp-maybe-compressed-blob", "sp-runtime", "sp-state-machine", "sp-timestamp", + "sp-tracing", "sp-trie", - "sp-version", "substrate-test-client", "substrate-test-utils", "tokio", @@ -1982,27 +2019,27 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "2.1.0" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d85653f070353a16313d0046f173f70d1aadd5b42600a14de626f0dfb3473a5" +checksum = "4a9b85542f99a2dfa2a1b8e192662741c9859a846b296bef1c92ef9b58b5a216" dependencies = [ "byteorder", "digest 0.8.1", "rand_core 0.5.1", - "subtle 2.4.0", + "subtle", "zeroize", ] [[package]] name = "curve25519-dalek" -version = "3.0.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8492de420e9e60bc9a1d66e2dbb91825390b738a388606600663fc529b4b307" +checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" dependencies = [ "byteorder", "digest 0.9.0", "rand_core 0.5.1", - "subtle 2.4.0", + "subtle", "zeroize", ] @@ -2014,9 +2051,9 @@ checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57" [[package]] name = "data-encoding-macro" -version = "0.1.10" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a94feec3d2ba66c0b6621bca8bc6f68415b1e5c69af3586fdd0af9fd9f29b17" +checksum = "86927b7cd2fe88fa698b87404b287ab98d1a0063a34071d92e575b72d3029aca" dependencies = [ "data-encoding", "data-encoding-macro-internal", @@ -2024,9 +2061,9 @@ dependencies = [ [[package]] name = "data-encoding-macro-internal" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f83e699727abca3c56e187945f303389590305ab2f0185ea445aa66e8d5f2a" +checksum = "a5bbed42daaa95e780b60a50546aa345b8413a1e46f9a40a12907d3598f038db" dependencies = [ "data-encoding", "syn", @@ -2045,13 +2082,14 @@ dependencies = [ [[package]] name = "derive_more" -version = "0.99.14" +version = "0.99.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc7b9cef1e351660e5443924e4f43ab25fbbed3e9a5f052df3677deb4d6b320" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" dependencies = [ "convert_case", "proc-macro2", "quote", + "rustc_version 0.4.0", "syn", ] @@ -2067,7 +2105,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" dependencies = [ - "generic-array 0.12.3", + "generic-array 0.12.4", ] [[package]] @@ -2081,9 +2119,9 @@ dependencies = [ [[package]] name = "directories" -version = "3.0.2" +version = "4.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e69600ff1703123957937708eb27f7a564e48885c537782722ed0ba3189ce1d7" +checksum = "f51c5d4ddabd36886dd3e1438cb358cdcb0d7c499cb99cb4ac2e38e18b5cb210" dependencies = [ "dirs-sys", ] @@ -2142,6 +2180,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" +[[package]] +name = "dtoa" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0" + [[package]] name = "dyn-clonable" version = "0.9.0" @@ -2171,9 +2215,9 @@ checksum = "ee2626afccd7561a06cf1367e2950c4718ea04565e20fb5029b6c7d8ad09abcf" [[package]] name = "ed25519" -version = "1.0.3" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37c66a534cbb46ab4ea03477eae19d5c22c01da8258030280b7bd9d8433fb6ef" +checksum = "74e1069e39f1454367eb2de793ed062fac4c35c2934b76a81d90dd9abcd28816" dependencies = [ "signature", ] @@ -2184,7 +2228,7 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" dependencies = [ - "curve25519-dalek 3.0.0", + "curve25519-dalek 3.2.0", "ed25519", "rand 0.7.3", "serde", @@ -2275,9 +2319,9 @@ checksum = "68b91989ae21441195d7d9b9993a2f9295c7e1a8c96255d8b729accddc124797" [[package]] name = "errno" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa68f2fb9cae9d37c9b2b3584aba698a2e97f72d7aef7b9f7aa71d8b54ce46fe" +checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" dependencies = [ "errno-dragonfly", "libc", @@ -2286,31 +2330,31 @@ dependencies = [ [[package]] name = "errno-dragonfly" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14ca354e36190500e1e1fb267c647932382b54053c50b14970856c0b00a35067" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" dependencies = [ - "gcc", + "cc", "libc", ] [[package]] name = "escargot" -version = "0.5.0" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74cf96bec282dcdb07099f7e31d9fed323bca9435a09aba7b6d99b7617bca96d" +checksum = "9ead7d8a70259beb627c1ffdd19b0372381f247f88e46a3bd52bb797182690b3" dependencies = [ - "lazy_static", "log", + "once_cell", "serde", "serde_json", ] [[package]] name = "ethbloom" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "779864b9c7f7ead1f092972c3257496c6a84b46dba2ce131dd8a282cb2cc5972" +checksum = "bfb684ac8fa8f6c5759f788862bb22ec6fe3cb392f6bfd08e3c64b603661e3f8" dependencies = [ "crunchy", "fixed-hash", @@ -2321,9 +2365,9 @@ dependencies = [ [[package]] name = "ethereum-types" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd6bde671199089e601e8d47e153368b893ef885f11f365a3261ec58153c211" +checksum = "05136f7057fe789f06e6d41d07b34e6f70d8c86e5693b60f97aaa6553553bdaf" dependencies = [ "ethbloom", "fixed-hash", @@ -2345,7 +2389,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e43f2f1833d64e33f15592464d6fdd70f349dda7b1a53088eb83cd94014008c5" dependencies = [ - "futures 0.3.17", + "futures 0.3.19", ] [[package]] @@ -2362,9 +2406,9 @@ checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" [[package]] name = "fastrand" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca5faf057445ce5c9d4329e382b2ce7ca38550ef3b73a5348362d5f24e0c7fe3" +checksum = "b394ed3d285a429378d3b384b9eb1285267e7df4b166df24b7a6939a04dc392e" dependencies = [ "instant", ] @@ -2395,12 +2439,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8ac3ff5224ef91f3c97e03eb1de2db82743427e91aaa5ac635f454f0b164f5a" dependencies = [ "either", - "futures 0.3.17", + "futures 0.3.19", "futures-timer 3.0.2", "log", "num-traits", "parity-scale-codec", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "scale-info", ] @@ -2418,15 +2462,15 @@ dependencies = [ [[package]] name = "fixedbitset" -version = "0.2.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d" +checksum = "398ea4fabe40b9b0d885340a2a991a44c8a645624075ad966d21f88688e2b69e" [[package]] name = "flate2" -version = "1.0.19" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7411863d55df97a419aa64cb4d2f167103ea9d767e2c54a1868b7ac3f6b47129" +checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f" dependencies = [ "cfg-if 1.0.0", "crc32fast", @@ -2444,16 +2488,16 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "fork-tree" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "parity-scale-codec", ] [[package]] name = "form_urlencoded" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ece68d15c92e84fa4f19d3780f1294e5ca82a78a6d515f1efaabcc144688be00" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" dependencies = [ "matches", "percent-encoding 2.1.0", @@ -2462,7 +2506,7 @@ dependencies = [ [[package]] name = "frame-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "frame-support", "frame-system", @@ -2472,6 +2516,7 @@ dependencies = [ "paste", "scale-info", "sp-api", + "sp-application-crypto", "sp-io", "sp-runtime", "sp-runtime-interface", @@ -2482,7 +2527,7 @@ dependencies = [ [[package]] name = "frame-benchmarking-cli" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "Inflector", "chrono", @@ -2508,7 +2553,7 @@ dependencies = [ [[package]] name = "frame-election-provider-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "frame-support", "frame-system", @@ -2522,7 +2567,7 @@ dependencies = [ [[package]] name = "frame-executive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "frame-support", "frame-system", @@ -2537,9 +2582,9 @@ dependencies = [ [[package]] name = "frame-metadata" -version = "14.0.0" +version = "14.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96616f82e069102b95a72c87de4c84d2f87ef7f0f20630e78ce3824436483110" +checksum = "37ed5e5c346de62ca5c184b4325a6600d1eaca210666e4606fe4e449574978d0" dependencies = [ "cfg-if 1.0.0", "parity-scale-codec", @@ -2550,7 +2595,7 @@ dependencies = [ [[package]] name = "frame-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "bitflags", "frame-metadata", @@ -2565,6 +2610,7 @@ dependencies = [ "smallvec", "sp-arithmetic", "sp-core", + "sp-core-hashing-proc-macro", "sp-inherents", "sp-io", "sp-runtime", @@ -2572,12 +2618,13 @@ dependencies = [ "sp-state-machine", "sp-std", "sp-tracing", + "tt-call", ] [[package]] name = "frame-support-procedural" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "Inflector", "frame-support-procedural-tools", @@ -2589,7 +2636,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "frame-support-procedural-tools-derive", "proc-macro-crate 1.1.0", @@ -2601,7 +2648,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools-derive" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "proc-macro2", "quote", @@ -2611,7 +2658,7 @@ dependencies = [ [[package]] name = "frame-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "frame-support", "log", @@ -2628,7 +2675,7 @@ dependencies = [ [[package]] name = "frame-system-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "frame-benchmarking", "frame-support", @@ -2643,7 +2690,7 @@ dependencies = [ [[package]] name = "frame-system-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "parity-scale-codec", "sp-api", @@ -2652,7 +2699,7 @@ dependencies = [ [[package]] name = "frame-try-runtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "frame-support", "sp-api", @@ -2662,9 +2709,9 @@ dependencies = [ [[package]] name = "fs-err" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcd1163ae48bda72a20ae26d66a04d3094135cadab911cff418ae5e33f253431" +checksum = "5ebd3504ad6116843b8375ad70df74e7bfe83cac77a1f3fe73200c844d43bfe0" [[package]] name = "fs-swap" @@ -2712,15 +2759,15 @@ checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" [[package]] name = "futures" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c7e4c2612746b0df8fed4ce0c69156021b704c9aefa360311c04e6e9e002eed" +checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678" [[package]] name = "futures" -version = "0.3.17" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12aa0eb539080d55c3f2d45a67c3b58b6b0773c1a3ca2dfec66d58c97fd66ca" +checksum = "28560757fe2bb34e79f907794bb6b22ae8b0e5c669b638a1132f2592b19035b4" dependencies = [ "futures-channel", "futures-core", @@ -2733,9 +2780,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.17" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888" +checksum = "ba3dda0b6588335f360afc675d0564c17a77a2bda81ca178a4b6081bd86c7f0b" dependencies = [ "futures-core", "futures-sink", @@ -2743,15 +2790,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.17" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d" +checksum = "d0c8ff0461b82559810cdccfde3215c3f373807f5e5232b71479bff7bb2583d7" [[package]] name = "futures-executor" -version = "0.3.17" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45025be030969d763025784f7f355043dc6bc74093e4ecc5000ca4dc50d8745c" +checksum = "29d6d2ff5bb10fb95c85b8ce46538a2e5f5e7fdc755623a7d4529ab8a4ed9d2a" dependencies = [ "futures-core", "futures-task", @@ -2761,33 +2808,31 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.17" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "522de2a0fe3e380f1bc577ba0474108faf3f6b18321dbf60b3b9c39a75073377" +checksum = "b1f9d34af5a1aac6fb380f735fe510746c38067c5bf16c7fd250280503c971b2" [[package]] name = "futures-lite" -version = "1.11.3" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4481d0cd0de1d204a4fa55e7d45f07b1d958abcb06714b3446438e2eff695fb" +checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48" dependencies = [ "fastrand", "futures-core", "futures-io", "memchr", "parking", - "pin-project-lite 0.2.4", + "pin-project-lite 0.2.7", "waker-fn", ] [[package]] name = "futures-macro" -version = "0.3.17" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18e4a4b95cea4b4ccbcf1c5675ca7c4ee4e9e75eb79944d07defde18068f79bb" +checksum = "6dbd947adfffb0efc70599b3ddcf7b5597bb5fa9e245eb99f62b3a5f7bb8bd3c" dependencies = [ - "autocfg", - "proc-macro-hack", "proc-macro2", "quote", "syn", @@ -2806,15 +2851,15 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.17" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36ea153c13024fe480590b3e3d4cad89a0cfacecc24577b68f86c6ced9c2bc11" +checksum = "e3055baccb68d74ff6480350f8d6eb8fcfa3aa11bdc1a1ae3afdd0514617d508" [[package]] name = "futures-task" -version = "0.3.17" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99" +checksum = "6ee7c6485c30167ce4dfb83ac568a849fe53274c831081476ee13e0dce1aad72" [[package]] name = "futures-timer" @@ -2830,12 +2875,11 @@ checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" [[package]] name = "futures-util" -version = "0.3.17" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481" +checksum = "d9b5cf40b47a271f77a8b1bec03ca09044d99d2372c0de244e66430761127164" dependencies = [ - "autocfg", - "futures 0.1.30", + "futures 0.1.31", "futures-channel", "futures-core", "futures-io", @@ -2843,37 +2887,16 @@ dependencies = [ "futures-sink", "futures-task", "memchr", - "pin-project-lite 0.2.4", + "pin-project-lite 0.2.7", "pin-utils", - "proc-macro-hack", - "proc-macro-nested", "slab", ] -[[package]] -name = "gcc" -version = "0.3.55" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" - -[[package]] -name = "generator" -version = "0.6.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cdc09201b2e8ca1b19290cf7e65de2246b8e91fb6874279722189c4de7b94dc" -dependencies = [ - "cc", - "libc", - "log", - "rustc_version 0.2.3", - "winapi 0.3.9", -] - [[package]] name = "generic-array" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" +checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" dependencies = [ "typenum", ] @@ -2903,9 +2926,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4060f4657be78b8e766215b02b18a2e862d83745545de804638e2b545e81aee6" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" dependencies = [ "cfg-if 1.0.0", "libc", @@ -2914,9 +2937,9 @@ dependencies = [ [[package]] name = "ghash" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b442c439366184de619215247d24e908912b175e824a530253845ac4c251a5c1" +checksum = "1583cc1656d7839fd3732b80cf4f38850336cdb9b8ded1cd399ca62958de3c99" dependencies = [ "opaque-debug 0.3.0", "polyval", @@ -2933,6 +2956,12 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "gimli" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" + [[package]] name = "glob" version = "0.3.0" @@ -2941,9 +2970,9 @@ checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" [[package]] name = "globset" -version = "0.4.6" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c152169ef1e421390738366d2f796655fec62621dabbd0fd476f905934061e4a" +checksum = "10463d9ff00a2a068db14231982f5132edebad0d7660cd956a1c30292dbcbfbd" dependencies = [ "aho-corasick", "bstr", @@ -2966,15 +2995,40 @@ dependencies = [ ] [[package]] -name = "handlebars" -version = "3.5.2" +name = "h2" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "964d0e99a61fe9b1b347389b77ebf8b7e1587b70293676aaca7d27e59b9073b2" +checksum = "8f072413d126e57991455e0a922b31e4c8ba7c2ffbebf6b78b4f8521397d65cd" +dependencies = [ + "bytes 1.1.0", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "half" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" + +[[package]] +name = "handlebars" +version = "4.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167fa173496c9eadd8749cca6f8339ac88e248f3ad2442791d0b743318a94fc0" dependencies = [ "log", "pest", "pest_derive", - "quick-error 2.0.0", + "quick-error 2.0.1", "serde", "serde_json", ] @@ -3005,18 +3059,18 @@ dependencies = [ [[package]] name = "heck" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cbf45460356b7deeb5e3415b5563308c0a9b057c85e12b06ad551f98d0a6ac" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" dependencies = [ "unicode-segmentation", ] [[package]] name = "hermit-abi" -version = "0.1.17" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" dependencies = [ "libc", ] @@ -3039,9 +3093,9 @@ dependencies = [ [[package]] name = "hex-literal" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21e4590e13640f19f249fe3e4eca5113bc4289f2497710378190e7f4bd96f45b" +checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" [[package]] name = "hex-literal-impl" @@ -3058,16 +3112,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b07f60793ff0a4d9cef0f18e63b5357e06209987153a64648c972c1e5aff336f" -[[package]] -name = "hmac" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695" -dependencies = [ - "crypto-mac 0.7.0", - "digest 0.8.1", -] - [[package]] name = "hmac" version = "0.8.1" @@ -3078,6 +3122,16 @@ dependencies = [ "digest 0.9.0", ] +[[package]] +name = "hmac" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" +dependencies = [ + "crypto-mac 0.11.1", + "digest 0.9.0", +] + [[package]] name = "hmac-drbg" version = "0.3.0" @@ -3102,24 +3156,24 @@ dependencies = [ [[package]] name = "http" -version = "0.2.2" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84129d298a6d57d246960ff8eb831ca4af3f96d29e2e28848dae275408658e26" +checksum = "1323096b05d41827dadeaee54c9981958c0f94e670bc94ed80037d1a7b8b186b" dependencies = [ - "bytes 0.5.6", + "bytes 1.1.0", "fnv", "itoa", ] [[package]] name = "http-body" -version = "0.4.2" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60daa14be0e0786db0f03a9e57cb404c9d756eed2b6c62b9ea98ec5743ec75a9" +checksum = "1ff4f84919677303da5f147645dbea6b1881f368d03ac84e1dc09031ebd7b2c6" dependencies = [ - "bytes 1.0.1", + "bytes 1.1.0", "http", - "pin-project-lite 0.2.4", + "pin-project-lite 0.2.7", ] [[package]] @@ -3130,9 +3184,9 @@ checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503" [[package]] name = "httpdate" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6456b8a6c8f33fee7d958fcd1b60d55b11940a79e63ae87013e6d22e26034440" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" [[package]] name = "humantime" @@ -3151,21 +3205,22 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.11" +version = "0.14.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b61cf2d1aebcf6e6352c97b81dc2244ca29194be1b276f5d8ad5c6330fffb11" +checksum = "b7ec3e62bdc98a2f0393a5048e4c30ef659440ea6e0e572965103e72bd836f55" dependencies = [ - "bytes 1.0.1", + "bytes 1.1.0", "futures-channel", "futures-core", "futures-util", + "h2", "http", "http-body", "httparse", "httpdate", "itoa", - "pin-project-lite 0.2.4", - "socket2 0.4.0", + "pin-project-lite 0.2.7", + "socket2 0.4.2", "tokio", "tower-service", "tracing", @@ -3202,9 +3257,9 @@ dependencies = [ [[package]] name = "idna" -version = "0.2.0" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" dependencies = [ "matches", "unicode-bidi", @@ -3213,9 +3268,9 @@ dependencies = [ [[package]] name = "if-addrs" -version = "0.6.5" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28538916eb3f3976311f5dfbe67b5362d0add1293d0a9cad17debf86f8e3aa48" +checksum = "2273e421f7c4f0fc99e1934fe4776f59d8df2972f4199d703fc0da9f2a9f73de" dependencies = [ "if-addrs-sys", "libc", @@ -3234,12 +3289,12 @@ dependencies = [ [[package]] name = "if-watch" -version = "0.2.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6d52908d4ea4ab2bc22474ba149bf1011c8e2c3ebc1ff593ae28ac44f494b6" +checksum = "ae8ab7f67bad3240049cb24fb9cb0b4c2c6af4c245840917fbbdededeee91179" dependencies = [ "async-io", - "futures 0.3.17", + "futures 0.3.19", "futures-lite", "if-addrs", "ipnet", @@ -3268,9 +3323,9 @@ dependencies = [ [[package]] name = "impl-serde" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b47ca4d2b6931707a55fce5cf66aff80e2178c8b63bbb4ecb5695cbc870ddf6f" +checksum = "4551f042f3438e64dbd6226b20527fc84a6e1fe65688b58746a2f53623f25f5c" dependencies = [ "serde", ] @@ -3299,18 +3354,18 @@ dependencies = [ [[package]] name = "instant" -version = "0.1.9" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ "cfg-if 1.0.0", ] [[package]] name = "integer-encoding" -version = "1.1.5" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f4ebd0bd29be0f11973e9b3e219005661042a019fd757798c36a47c87852625" +checksum = "90c11140ffea82edce8dcd74137ce9324ec24b3cf0175fc9d7e29164da9915b8" [[package]] name = "integer-sqrt" @@ -3327,10 +3382,20 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64fa110ec7b8f493f416eed552740d10e7030ad5f63b2308f82c9608ec2df275" dependencies = [ - "futures 0.3.17", + "futures 0.3.19", "futures-timer 2.0.2", ] +[[package]] +name = "io-lifetimes" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "278e90d6f8a6c76a8334b336e306efa3c5f2b604048cbfd486d6f49878e3af14" +dependencies = [ + "rustc_version 0.4.0", + "winapi 0.3.9", +] + [[package]] name = "iovec" version = "0.1.4" @@ -3342,9 +3407,9 @@ dependencies = [ [[package]] name = "ip_network" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09b746553d2f4a1ca26fab939943ddfb217a091f34f53571620a8e3d30691303" +checksum = "aa2f047c0a98b2f299aa5d6d7088443570faae494e9ae1305e48be000c9e0eb1" [[package]] name = "ipconfig" @@ -3360,39 +3425,39 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47be2f14c678be2fdcab04ab1171db51b2762ce6f0a8ee87c8dd4a04ed216135" +checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9" [[package]] name = "itertools" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d572918e350e82412fe766d24b15e6682fb2ed2bbe018280caa810397cb319" +checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf" dependencies = [ "either", ] [[package]] name = "itoa" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" [[package]] name = "jobserver" -version = "0.1.21" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c71313ebb9439f74b00d9d2dcec36440beaf57a6aa0623068441dd7cd81a7f2" +checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" dependencies = [ "libc", ] [[package]] name = "js-sys" -version = "0.3.50" +version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d99f9e3e84b8f67f846ef5b4cbbc3b1c29f6c759fcbce6f01aa0e73d932a24c" +checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84" dependencies = [ "wasm-bindgen", ] @@ -3404,7 +3469,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2b99d4207e2a04fb4581746903c2bb7eb376f88de9c699d0f3e10feeac0cd3a" dependencies = [ "derive_more", - "futures 0.3.17", + "futures 0.3.19", "jsonrpc-core", "jsonrpc-pubsub", "log", @@ -3419,7 +3484,7 @@ version = "18.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14f7f76aef2d054868398427f6c54943cf3d1caa9a7ec7d0c38d69df97a965eb" dependencies = [ - "futures 0.3.17", + "futures 0.3.19", "futures-executor", "futures-util", "log", @@ -3434,7 +3499,7 @@ version = "18.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b51da17abecbdab3e3d4f26b01c5ec075e88d3abe3ab3b05dc9aa69392764ec0" dependencies = [ - "futures 0.3.17", + "futures 0.3.19", "jsonrpc-client-transports", ] @@ -3456,13 +3521,13 @@ version = "18.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1dea6e07251d9ce6a552abfb5d7ad6bc290a4596c8dcc3d795fae2bbdc1f3ff" dependencies = [ - "futures 0.3.17", + "futures 0.3.19", "hyper", "jsonrpc-core", "jsonrpc-server-utils", "log", "net2", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "unicase", ] @@ -3472,12 +3537,12 @@ version = "18.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "382bb0206323ca7cda3dcd7e245cea86d37d02457a02a975e3378fb149a48845" dependencies = [ - "futures 0.3.17", + "futures 0.3.19", "jsonrpc-core", "jsonrpc-server-utils", "log", "parity-tokio-ipc", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "tower-service", ] @@ -3487,11 +3552,11 @@ version = "18.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240f87695e6c6f62fb37f05c02c04953cf68d6408b8c1c89de85c7a0125b1011" dependencies = [ - "futures 0.3.17", + "futures 0.3.19", "jsonrpc-core", "lazy_static", "log", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "rand 0.7.3", "serde", ] @@ -3502,8 +3567,8 @@ version = "18.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa4fdea130485b572c39a460d50888beb00afb3e35de23ccd7fad8ff19f0e0d4" dependencies = [ - "bytes 1.0.1", - "futures 0.3.17", + "bytes 1.1.0", + "futures 0.3.19", "globset", "jsonrpc-core", "lazy_static", @@ -3520,23 +3585,34 @@ version = "18.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f892c7d766369475ab7b0669f417906302d7c0fb521285c0a0c92e52e7c8e946" dependencies = [ - "futures 0.3.17", + "futures 0.3.19", "jsonrpc-core", "jsonrpc-server-utils", "log", "parity-ws", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "slab", ] [[package]] -name = "jsonrpsee-proc-macros" -version = "0.3.1" +name = "jsonrpsee" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8edb341d35279b59c79d7fe9e060a51aec29d45af99cc7c72ea7caa350fa71a4" +checksum = "6373a33d987866ccfe1af4bc11b089dce941764313f9fd8b7cf13fcb51b72dc5" dependencies = [ - "Inflector", - "bae", + "jsonrpsee-proc-macros", + "jsonrpsee-types", + "jsonrpsee-utils", + "jsonrpsee-ws-client", +] + +[[package]] +name = "jsonrpsee-proc-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d802063f7a3c867456955f9d2f15eb3ee0edb5ec9ec2b5526324756759221c0f" +dependencies = [ + "log", "proc-macro-crate 1.1.0", "proc-macro2", "quote", @@ -3545,10 +3621,11 @@ dependencies = [ [[package]] name = "jsonrpsee-types" -version = "0.3.1" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cc738fd55b676ada3271ef7c383a14a0867a2a88b0fa941311bf5fc0a29d498" +checksum = "62f778cf245158fbd8f5d50823a2e9e4c708a40be164766bd35e9fb1d86715b2" dependencies = [ + "anyhow", "async-trait", "beef", "futures-channel", @@ -3557,32 +3634,43 @@ dependencies = [ "log", "serde", "serde_json", - "soketto 0.6.0", + "soketto", "thiserror", ] [[package]] -name = "jsonrpsee-ws-client" -version = "0.3.1" +name = "jsonrpsee-utils" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9841352dbecf4c2ed5dc71698df9f1660262ae4e0b610e968602529bdbcf7b30" +checksum = "0109c4f972058f3b1925b73a17210aff7b63b65967264d0045d15ee88fe84f0c" dependencies = [ + "arrayvec 0.7.2", + "beef", + "jsonrpsee-types", +] + +[[package]] +name = "jsonrpsee-ws-client" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "559aa56fc402af206c00fc913dc2be1d9d788dcde045d14df141a535245d35ef" +dependencies = [ + "arrayvec 0.7.2", "async-trait", "fnv", - "futures 0.3.17", + "futures 0.3.19", + "http", "jsonrpsee-types", "log", "pin-project 1.0.8", - "rustls", "rustls-native-certs", "serde", "serde_json", - "soketto 0.6.0", + "soketto", "thiserror", "tokio", "tokio-rustls", "tokio-util", - "url 2.2.0", ] [[package]] @@ -3603,11 +3691,11 @@ dependencies = [ [[package]] name = "kusama-runtime" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "beefy-primitives", - "bitvec 0.20.1", + "bitvec", "frame-benchmarking", "frame-election-provider-support", "frame-executive", @@ -3616,7 +3704,8 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal 0.3.3", + "hex-literal 0.3.4", + "kusama-runtime-constants", "log", "pallet-authority-discovery", "pallet-authorship", @@ -3639,6 +3728,7 @@ dependencies = [ "pallet-nicks", "pallet-offences", "pallet-offences-benchmarking", + "pallet-preimage", "pallet-proxy", "pallet-recovery", "pallet-scheduler", @@ -3687,6 +3777,18 @@ dependencies = [ "xcm-executor", ] +[[package]] +name = "kusama-runtime-constants" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" +dependencies = [ + "frame-support", + "polkadot-primitives", + "polkadot-runtime-common", + "smallvec", + "sp-runtime", +] + [[package]] name = "kv-log-macro" version = "1.0.7" @@ -3714,7 +3816,7 @@ checksum = "c3b6b85fc643f5acd0bffb2cc8a6d150209379267af0d41db72170021841f9f5" dependencies = [ "kvdb", "parity-util-mem", - "parking_lot 0.11.1", + "parking_lot 0.11.2", ] [[package]] @@ -3729,7 +3831,7 @@ dependencies = [ "num_cpus", "owning_ref", "parity-util-mem", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "regex", "rocksdb", "smallvec", @@ -3749,9 +3851,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.104" +version = "0.2.112" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b2f96d100e1cf1929e7719b7edb3b90ab5298072638fccd77be9ce942ecdfce" +checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" [[package]] name = "libloading" @@ -3765,9 +3867,9 @@ dependencies = [ [[package]] name = "libloading" -version = "0.7.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f84d96438c15fcd6c3f244c8fce01d1e2b9c6b5623e9c711dc9286d8fc92d6a" +checksum = "afe203d669ec979b7128619bae5a63b7b42e9203c1b29146079ee05e2f604b52" dependencies = [ "cfg-if 1.0.0", "winapi 0.3.9", @@ -3781,13 +3883,13 @@ checksum = "c7d73b3f436185384286bd8098d17ec07c9a7d2388a6599f824d8502b529702a" [[package]] name = "libp2p" -version = "0.39.1" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9004c06878ef8f3b4b4067e69a140d87ed20bf777287f82223e49713b36ee433" +checksum = "3bec54343492ba5940a6c555e512c6721139835d28c59bc22febece72dfd0d9d" dependencies = [ "atomic", - "bytes 1.0.1", - "futures 0.3.17", + "bytes 1.1.0", + "futures 0.3.19", "lazy_static", "libp2p-core", "libp2p-deflate", @@ -3797,12 +3899,14 @@ dependencies = [ "libp2p-identify", "libp2p-kad", "libp2p-mdns", + "libp2p-metrics", "libp2p-mplex", "libp2p-noise", "libp2p-ping", "libp2p-plaintext", "libp2p-pnet", "libp2p-relay", + "libp2p-rendezvous", "libp2p-request-response", "libp2p-swarm", "libp2p-swarm-derive", @@ -3812,7 +3916,7 @@ dependencies = [ "libp2p-websocket", "libp2p-yamux", "multiaddr", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "pin-project 1.0.8", "smallvec", "wasm-timer", @@ -3820,57 +3924,57 @@ dependencies = [ [[package]] name = "libp2p-core" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af9b4abdeaa420593a297c8592f63fad4234f4b88dc9343b8fd8e736c35faa59" +checksum = "bef22d9bba1e8bcb7ec300073e6802943fe8abb8190431842262b5f1c30abba1" dependencies = [ "asn1_der", "bs58", "ed25519-dalek", "either", "fnv", - "futures 0.3.17", + "futures 0.3.19", "futures-timer 3.0.2", "lazy_static", - "libsecp256k1 0.5.0", + "libsecp256k1", "log", "multiaddr", "multihash 0.14.0", "multistream-select", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "pin-project 1.0.8", "prost", "prost-build", - "rand 0.7.3", + "rand 0.8.4", "ring", "rw-stream-sink", "sha2 0.9.8", "smallvec", "thiserror", - "unsigned-varint 0.7.0", + "unsigned-varint 0.7.1", "void", "zeroize", ] [[package]] name = "libp2p-deflate" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66097fccc0b7f8579f90a03ea76ba6196332ea049fd07fd969490a06819dcdc8" +checksum = "51a800adb195f33de63f4b17b63fe64cfc23bf2c6a0d3d0d5321328664e65197" dependencies = [ "flate2", - "futures 0.3.17", + "futures 0.3.19", "libp2p-core", ] [[package]] name = "libp2p-dns" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58ff08b3196b85a17f202d80589e93b1660a574af67275706657fdc762e42c32" +checksum = "bb8f89d15cb6e3c5bc22afff7513b11bab7856f2872d3cfba86f7f63a06bc498" dependencies = [ "async-std-resolver", - "futures 0.3.17", + "futures 0.3.19", "libp2p-core", "log", "smallvec", @@ -3879,13 +3983,13 @@ dependencies = [ [[package]] name = "libp2p-floodsub" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "404eca8720967179dac7a5b4275eb91f904a53859c69ca8d018560ad6beb214f" +checksum = "aab3d7210901ea51b7bae2b581aa34521797af8c4ec738c980bda4a06434067f" dependencies = [ "cuckoofilter", "fnv", - "futures 0.3.17", + "futures 0.3.19", "libp2p-core", "libp2p-swarm", "log", @@ -3897,16 +4001,16 @@ dependencies = [ [[package]] name = "libp2p-gossipsub" -version = "0.32.0" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1cc48709bcbc3a3321f08a73560b4bbb4166a7d56f6fdb615bc775f4f91058e" +checksum = "dfeead619eb5dac46e65acc78c535a60aaec803d1428cca6407c3a4fc74d698d" dependencies = [ "asynchronous-codec 0.6.0", - "base64 0.13.0", + "base64", "byteorder", - "bytes 1.0.1", + "bytes 1.1.0", "fnv", - "futures 0.3.17", + "futures 0.3.19", "hex_fmt", "libp2p-core", "libp2p-swarm", @@ -3917,20 +4021,21 @@ dependencies = [ "regex", "sha2 0.9.8", "smallvec", - "unsigned-varint 0.7.0", + "unsigned-varint 0.7.1", "wasm-timer", ] [[package]] name = "libp2p-identify" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7b61f6cf07664fb97016c318c4d4512b3dd4cc07238607f3f0163245f99008e" +checksum = "cca1275574183f288ff8b72d535d5ffa5ea9292ef7829af8b47dcb197c7b0dcd" dependencies = [ - "futures 0.3.17", + "futures 0.3.19", "libp2p-core", "libp2p-swarm", "log", + "lru 0.6.6", "prost", "prost-build", "smallvec", @@ -3939,16 +4044,16 @@ dependencies = [ [[package]] name = "libp2p-kad" -version = "0.31.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50ed78489c87924235665a0ab345b298ee34dff0f7ad62c0ba6608b2144fb75e" +checksum = "a2297dc0ca285f3a09d1368bde02449e539b46f94d32d53233f53f6625bcd3ba" dependencies = [ "arrayvec 0.5.2", "asynchronous-codec 0.6.0", - "bytes 1.0.1", + "bytes 1.1.0", "either", "fnv", - "futures 0.3.17", + "futures 0.3.19", "libp2p-core", "libp2p-swarm", "log", @@ -3958,21 +4063,21 @@ dependencies = [ "sha2 0.9.8", "smallvec", "uint", - "unsigned-varint 0.7.0", + "unsigned-varint 0.7.1", "void", "wasm-timer", ] [[package]] name = "libp2p-mdns" -version = "0.31.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a29e6cbc2a24b8471b6567e580a0e8e7b70a6d0f0ea2be0844d1e842d7d4fa33" +checksum = "14c864b64bdc8a84ff3910a0df88e6535f256191a450870f1e7e10cbf8e64d45" dependencies = [ "async-io", "data-encoding", "dns-parser", - "futures 0.3.17", + "futures 0.3.19", "if-watch", "lazy_static", "libp2p-core", @@ -3980,37 +4085,51 @@ dependencies = [ "log", "rand 0.8.4", "smallvec", - "socket2 0.4.0", + "socket2 0.4.2", "void", ] [[package]] -name = "libp2p-mplex" -version = "0.29.0" +name = "libp2p-metrics" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "313d9ea526c68df4425f580024e67a9d3ffd49f2c33de5154b1f5019816f7a99" +checksum = "4af432fcdd2f8ba4579b846489f8f0812cfd738ced2c0af39df9b1c48bbb6ab2" +dependencies = [ + "libp2p-core", + "libp2p-identify", + "libp2p-kad", + "libp2p-ping", + "libp2p-swarm", + "open-metrics-client", +] + +[[package]] +name = "libp2p-mplex" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f2cd64ef597f40e14bfce0497f50ecb63dd6d201c61796daeb4227078834fbf" dependencies = [ "asynchronous-codec 0.6.0", - "bytes 1.0.1", - "futures 0.3.17", + "bytes 1.1.0", + "futures 0.3.19", "libp2p-core", "log", "nohash-hasher", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "rand 0.7.3", "smallvec", - "unsigned-varint 0.7.0", + "unsigned-varint 0.7.1", ] [[package]] name = "libp2p-noise" -version = "0.32.0" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f1db7212f342b6ba7c981cc40e31f76e9e56cb48e65fa4c142ecaca5839523e" +checksum = "a8772c7a99088221bb7ca9c5c0574bf55046a7ab4c319f3619b275f28c8fb87a" dependencies = [ - "bytes 1.0.1", - "curve25519-dalek 3.0.0", - "futures 0.3.17", + "bytes 1.1.0", + "curve25519-dalek 3.2.0", + "futures 0.3.19", "lazy_static", "libp2p-core", "log", @@ -4026,11 +4145,11 @@ dependencies = [ [[package]] name = "libp2p-ping" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2482cfd9eb0b7a0baaf3e7b329dc4f2785181a161b1a47b7192f8d758f54a439" +checksum = "80ef7b0ec5cf06530d9eb6cf59ae49d46a2c45663bde31c25a12f682664adbcf" dependencies = [ - "futures 0.3.17", + "futures 0.3.19", "libp2p-core", "libp2p-swarm", "log", @@ -4041,28 +4160,28 @@ dependencies = [ [[package]] name = "libp2p-plaintext" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13b4783e5423870b9a5c199f65a7a3bc66d86ab56b2b9beebf3c338d889cf8e4" +checksum = "5fba1a6ff33e4a274c89a3b1d78b9f34f32af13265cc5c46c16938262d4e945a" dependencies = [ "asynchronous-codec 0.6.0", - "bytes 1.0.1", - "futures 0.3.17", + "bytes 1.1.0", + "futures 0.3.19", "libp2p-core", "log", "prost", "prost-build", - "unsigned-varint 0.7.0", + "unsigned-varint 0.7.1", "void", ] [[package]] name = "libp2p-pnet" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07cb4dd4b917e5b40ddefe49b96b07adcd8d342e0317011d175b7b2bb1dcc974" +checksum = "0f1a458bbda880107b5b36fcb9b5a1ef0c329685da0e203ed692a8ebe64cc92c" dependencies = [ - "futures 0.3.17", + "futures 0.3.19", "log", "pin-project 1.0.8", "rand 0.7.3", @@ -4072,13 +4191,13 @@ dependencies = [ [[package]] name = "libp2p-relay" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0133f6cfd81cdc16e716de2982e012c62e6b9d4f12e41967b3ee361051c622aa" +checksum = "2852b61c90fa8ce3c8fcc2aba76e6cefc20d648f9df29157d6b3a916278ef3e3" dependencies = [ "asynchronous-codec 0.6.0", - "bytes 1.0.1", - "futures 0.3.17", + "bytes 1.1.0", + "futures 0.3.19", "futures-timer 3.0.2", "libp2p-core", "libp2p-swarm", @@ -4088,39 +4207,60 @@ dependencies = [ "prost-build", "rand 0.7.3", "smallvec", - "unsigned-varint 0.7.0", + "unsigned-varint 0.7.1", + "void", + "wasm-timer", +] + +[[package]] +name = "libp2p-rendezvous" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14a6d2b9e7677eff61dc3d2854876aaf3976d84a01ef6664b610c77a0c9407c5" +dependencies = [ + "asynchronous-codec 0.6.0", + "bimap", + "futures 0.3.19", + "libp2p-core", + "libp2p-swarm", + "log", + "prost", + "prost-build", + "rand 0.8.4", + "sha2 0.9.8", + "thiserror", + "unsigned-varint 0.7.1", "void", "wasm-timer", ] [[package]] name = "libp2p-request-response" -version = "0.12.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06cdae44b6821466123af93cbcdec7c9e6ba9534a8af9cdc296446d39416d241" +checksum = "a877a4ced6d46bf84677e1974e8cf61fb434af73b2e96fb48d6cb6223a4634d8" dependencies = [ "async-trait", - "bytes 1.0.1", - "futures 0.3.17", + "bytes 1.1.0", + "futures 0.3.19", "libp2p-core", "libp2p-swarm", "log", - "lru 0.6.6", - "minicbor", + "lru 0.7.1", "rand 0.7.3", "smallvec", - "unsigned-varint 0.7.0", + "unsigned-varint 0.7.1", "wasm-timer", ] [[package]] name = "libp2p-swarm" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7083861341e1555467863b4cd802bea1e8c4787c0f7b5110097d0f1f3248f9a9" +checksum = "3f5184a508f223bc100a12665517773fb8730e9f36fc09eefb670bf01b107ae9" dependencies = [ "either", - "futures 0.3.17", + "futures 0.3.19", "libp2p-core", "log", "rand 0.7.3", @@ -4131,9 +4271,9 @@ dependencies = [ [[package]] name = "libp2p-swarm-derive" -version = "0.24.0" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab8cb308d4fc854869f5abb54fdab0833d2cf670d407c745849dc47e6e08d79c" +checksum = "072c290f727d39bdc4e9d6d1c847978693d25a673bd757813681e33e5f6c00c2" dependencies = [ "quote", "syn", @@ -4141,40 +4281,40 @@ dependencies = [ [[package]] name = "libp2p-tcp" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79edd26b6b4bb5feee210dcda562dca186940dfecb0024b979c3f50824b3bf28" +checksum = "7399c5b6361ef525d41c11fcf51635724f832baf5819b30d3d873eabb4fbae4b" dependencies = [ "async-io", - "futures 0.3.17", + "futures 0.3.19", "futures-timer 3.0.2", "if-watch", "ipnet", "libc", "libp2p-core", "log", - "socket2 0.4.0", + "socket2 0.4.2", ] [[package]] name = "libp2p-uds" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "280e793440dd4e9f273d714f4497325c72cddb0fe85a49f9a03c88f41dd20182" +checksum = "b8b7563e46218165dfd60f64b96f7ce84590d75f53ecbdc74a7dd01450dc5973" dependencies = [ "async-std", - "futures 0.3.17", + "futures 0.3.19", "libp2p-core", "log", ] [[package]] name = "libp2p-wasm-ext" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f553b7140fad3d7a76f50497b0ea591e26737d9607428a75509fc191e4d1b1f6" +checksum = "1008a302b73c5020251f9708c653f5ed08368e530e247cc9cd2f109ff30042cf" dependencies = [ - "futures 0.3.17", + "futures 0.3.19", "js-sys", "libp2p-core", "parity-send-wrapper", @@ -4184,31 +4324,31 @@ dependencies = [ [[package]] name = "libp2p-websocket" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddf99dcbf5063e9d59087f61b1e85c686ceab2f5abedb472d32288065c0e5e27" +checksum = "22e12df82d1ed64969371a9e65ea92b91064658604cc2576c2757f18ead9a1cf" dependencies = [ "either", - "futures 0.3.17", + "futures 0.3.19", "futures-rustls", "libp2p-core", "log", "quicksink", "rw-stream-sink", - "soketto 0.4.2", - "url 2.2.0", + "soketto", + "url 2.2.2", "webpki-roots", ] [[package]] name = "libp2p-yamux" -version = "0.33.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "214cc0dd9c37cbed27f0bb1eba0c41bbafdb93a8be5e9d6ae1e6b4b42cd044bf" +checksum = "4e7362abb8867d7187e7e93df17f460d554c997fc5c8ac57dc1259057f6889af" dependencies = [ - "futures 0.3.17", + "futures 0.3.19", "libp2p-core", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "thiserror", "yamux", ] @@ -4225,44 +4365,6 @@ dependencies = [ "libc", ] -[[package]] -name = "libsecp256k1" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd1137239ab33b41aa9637a88a28249e5e70c40a42ccc92db7f12cc356c1fcd7" -dependencies = [ - "arrayref", - "base64 0.12.3", - "digest 0.9.0", - "hmac-drbg", - "libsecp256k1-core 0.2.2", - "libsecp256k1-gen-ecmult 0.2.1", - "libsecp256k1-gen-genmult 0.2.1", - "rand 0.7.3", - "serde", - "sha2 0.9.8", - "typenum", -] - -[[package]] -name = "libsecp256k1" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9d220bc1feda2ac231cb78c3d26f27676b8cf82c96971f7aeef3d0cf2797c73" -dependencies = [ - "arrayref", - "base64 0.12.3", - "digest 0.9.0", - "hmac-drbg", - "libsecp256k1-core 0.2.2", - "libsecp256k1-gen-ecmult 0.2.1", - "libsecp256k1-gen-genmult 0.2.1", - "rand 0.7.3", - "serde", - "sha2 0.9.8", - "typenum", -] - [[package]] name = "libsecp256k1" version = "0.7.0" @@ -4270,29 +4372,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b0452aac8bab02242429380e9b2f94ea20cea2b37e2c1777a1358799bbe97f37" dependencies = [ "arrayref", - "base64 0.13.0", + "base64", "digest 0.9.0", "hmac-drbg", - "libsecp256k1-core 0.3.0", - "libsecp256k1-gen-ecmult 0.3.0", - "libsecp256k1-gen-genmult 0.3.0", + "libsecp256k1-core", + "libsecp256k1-gen-ecmult", + "libsecp256k1-gen-genmult", "rand 0.8.4", "serde", "sha2 0.9.8", "typenum", ] -[[package]] -name = "libsecp256k1-core" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0f6ab710cec28cef759c5f18671a27dae2a5f952cdaaee1d8e2908cb2478a80" -dependencies = [ - "crunchy", - "digest 0.9.0", - "subtle 2.4.0", -] - [[package]] name = "libsecp256k1-core" version = "0.3.0" @@ -4301,16 +4392,7 @@ checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" dependencies = [ "crunchy", "digest 0.9.0", - "subtle 2.4.0", -] - -[[package]] -name = "libsecp256k1-gen-ecmult" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccab96b584d38fac86a83f07e659f0deafd0253dc096dab5a36d53efe653c5c3" -dependencies = [ - "libsecp256k1-core 0.2.2", + "subtle", ] [[package]] @@ -4319,16 +4401,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" dependencies = [ - "libsecp256k1-core 0.3.0", -] - -[[package]] -name = "libsecp256k1-gen-genmult" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67abfe149395e3aa1c48a2beb32b068e2334402df8181f818d3aee2b304c4f5d" -dependencies = [ - "libsecp256k1-core 0.2.2", + "libsecp256k1-core", ] [[package]] @@ -4337,14 +4410,14 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" dependencies = [ - "libsecp256k1-core 0.3.0", + "libsecp256k1-core", ] [[package]] name = "libz-sys" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "602113192b08db8f38796c4e85c39e960c145965140e918018bcde1952429655" +checksum = "de5435b8549c16d423ed0c03dbaafe57cf6c3344744f1242520d59c9d8ecec66" dependencies = [ "cc", "pkg-config", @@ -4368,14 +4441,20 @@ dependencies = [ [[package]] name = "linregress" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e6e407dadb4ca4b31bc69c27aff00e7ca4534fdcee855159b039a7cebb5f395" +checksum = "d6c601a85f5ecd1aba625247bca0031585fb1c446461b142878a16f8245ddeb8" dependencies = [ "nalgebra", "statrs", ] +[[package]] +name = "linux-raw-sys" +version = "0.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "687387ff42ec7ea4f2149035a5675fedb675d26f98db90a1846ac63d3addb5f5" + [[package]] name = "lock_api" version = "0.3.4" @@ -4387,9 +4466,9 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.2" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd96ffd135b2fd7b973ac026d28085defbe8983df057ced3eb4f2130b0831312" +checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" dependencies = [ "scopeguard", ] @@ -4404,19 +4483,6 @@ dependencies = [ "value-bag", ] -[[package]] -name = "loom" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0e8460f2f2121162705187214720353c517b97bdfb3494c0b1e33d83ebe4bed" -dependencies = [ - "cfg-if 0.1.10", - "generator", - "scoped-tls", - "serde", - "serde_json", -] - [[package]] name = "lru" version = "0.6.6" @@ -4428,9 +4494,9 @@ dependencies = [ [[package]] name = "lru" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c748cfe47cb8da225c37595b3108bea1c198c84aaae8ea0ba76d01dda9fc803" +checksum = "469898e909a1774d844793b347135a0cd344ca2f69d082013ecb8061a2229a3a" dependencies = [ "hashbrown", ] @@ -4496,15 +4562,15 @@ dependencies = [ [[package]] name = "matches" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" [[package]] name = "matrixmultiply" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a8a15b776d9dfaecd44b03c5828c2199cddff5247215858aac14624f8d6b741" +checksum = "add85d4dd35074e6fedc608f8c8f513a3548619a9024b751949ef0e8e45a4d84" dependencies = [ "rawpointer", ] @@ -4517,27 +4583,36 @@ checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" [[package]] name = "memmap2" -version = "0.2.0" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e73be3b7d04a0123e933fea1d50d126cc7196bbc0362c0ce426694f777194eee" +checksum = "723e3ebdcdc5c023db1df315364573789f8857c11b631a2fdfad7c00f5c046b4" +dependencies = [ + "libc", +] + +[[package]] +name = "memmap2" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4647a11b578fead29cdbb34d4adef8dd3dc35b876c9c6d5240d83f205abfe96e" dependencies = [ "libc", ] [[package]] name = "memoffset" -version = "0.6.1" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "157b4208e3059a8f9e78d559edc658e13df41410cb3ae03979c83130067fdd87" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" dependencies = [ "autocfg", ] [[package]] name = "memory-db" -version = "0.27.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de006e09d04fc301a5f7e817b75aa49801c4479a8af753764416b085337ddcc5" +checksum = "d505169b746dacf02f7d14d8c80b34edfd8212159c63d23c977739a0d960c626" dependencies = [ "hash-db", "hashbrown", @@ -4561,9 +4636,9 @@ checksum = "71d96e3f3c0b6325d8ccd83c33b28acb183edcb6c67938ba104ec546854b0882" [[package]] name = "merlin" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6feca46f4fa3443a01769d768727f10c10a20fdb65e52dc16a81f0c8269bb78" +checksum = "4e261cf0f8b3c42ded9f7d2bb59dea03aa52bc8a1cbc7482f9fc3fd1229d3b42" dependencies = [ "byteorder", "keccak", @@ -4573,11 +4648,11 @@ dependencies = [ [[package]] name = "metered-channel" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "derive_more", - "futures 0.3.17", + "futures 0.3.19", "futures-timer 3.0.2", "thiserror", "tracing", @@ -4585,40 +4660,26 @@ dependencies = [ [[package]] name = "mick-jaeger" -version = "0.1.4" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c023c3f16109e7f33aa451f773fd61070e265b4977d0b6e344a51049296dd7df" +checksum = "fd2c2cc134e57461f0898b0e921f0a7819b5e3f3a4335b9aa390ce81a5f36fb9" dependencies = [ - "futures 0.3.17", - "rand 0.7.3", + "futures 0.3.19", + "rand 0.8.4", "thrift", ] [[package]] -name = "minicbor" -version = "0.8.0" +name = "minimal-lexical" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea79ce4ab9f445ec6b71833a2290ac0a29c9dde0fa7cae4c481eecae021d9bd9" -dependencies = [ - "minicbor-derive", -] - -[[package]] -name = "minicbor-derive" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce18b5423c573a13e80cb3046ea0af6379ef725dc3af4886bdb8f4e5093068" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f2d26ec3309788e423cfbf68ad1800f061638098d76a83681af979dc4eda19d" +checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" dependencies = [ "adler", "autocfg", @@ -4645,13 +4706,13 @@ dependencies = [ [[package]] name = "mio" -version = "0.7.13" +version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c2bdb6314ec10835cd3293dd268473a835c02b7b352e788be788b3c6ca6bb16" +checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc" dependencies = [ "libc", "log", - "miow 0.3.6", + "miow 0.3.7", "ntapi", "winapi 0.3.9", ] @@ -4682,19 +4743,18 @@ dependencies = [ [[package]] name = "miow" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a33c1b55807fbed163481b5ba66db4b2fa6cde694a5027be10fb724206c5897" +checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" dependencies = [ - "socket2 0.3.19", "winapi 0.3.9", ] [[package]] name = "more-asserts" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0debeb9fcf88823ea64d64e4a815ab1643f33127d995978e099942ce38f25238" +checksum = "7843ec2de400bcbc6a6328c958dc38e5359da6e93e72e37bc5246bf1ae776389" [[package]] name = "multiaddr" @@ -4710,8 +4770,8 @@ dependencies = [ "percent-encoding 2.1.0", "serde", "static_assertions", - "unsigned-varint 0.7.0", - "url 2.2.0", + "unsigned-varint 0.7.1", + "url 2.2.2", ] [[package]] @@ -4752,7 +4812,7 @@ dependencies = [ "generic-array 0.14.4", "multihash-derive", "sha2 0.9.8", - "unsigned-varint 0.7.0", + "unsigned-varint 0.7.1", ] [[package]] @@ -4762,7 +4822,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "424f6e86263cd5294cbd7f1e95746b95aca0e0d66bff31e5a40d6baa87b4aa99" dependencies = [ "proc-macro-crate 1.1.0", - "proc-macro-error 1.0.4", + "proc-macro-error", "proc-macro2", "quote", "syn", @@ -4771,22 +4831,22 @@ dependencies = [ [[package]] name = "multimap" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1255076139a83bb467426e7f8d0134968a8118844faa755985e077cf31850333" +checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" [[package]] name = "multistream-select" -version = "0.10.0" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10ddc0eb0117736f19d556355464fc87efc8ad98b29e3fd84f02531eb6e90840" +checksum = "56a336acba8bc87c8876f6425407dbbe6c417bf478b22015f8fb0994ef3bc0ab" dependencies = [ - "bytes 1.0.1", - "futures 0.3.17", + "bytes 1.1.0", + "futures 0.3.19", "log", "pin-project 1.0.8", "smallvec", - "unsigned-varint 0.6.0", + "unsigned-varint 0.7.1", ] [[package]] @@ -4827,16 +4887,6 @@ dependencies = [ "rand 0.8.4", ] -[[package]] -name = "nb-connect" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8123a81538e457d44b933a02faf885d3fe8408806b23fa700e8f01c6c3a98998" -dependencies = [ - "libc", - "winapi 0.3.9", -] - [[package]] name = "net2" version = "0.2.37" @@ -4864,7 +4914,7 @@ dependencies = [ [[package]] name = "node-primitives" version = "2.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#66296a0af0aede07c27104e6174a3534b15f14aa" +source = "git+https://github.com/paritytech/substrate?branch=master#b03e8bcf151bbf4c20a7d7faa782366fc3554d58" dependencies = [ "frame-system", "parity-scale-codec", @@ -4888,13 +4938,12 @@ checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" [[package]] name = "nom" -version = "6.1.2" +version = "7.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7413f999671bd4745a7b624bd370a569fb6bc574b23c83a3c5ed2e453f3d5e2" +checksum = "1b1d11e1ef389c76fe5b81bcaf2ea32cf88b62bc494e19f493d0b30e7a930109" dependencies = [ - "bitvec 0.19.5", - "funty", "memchr", + "minimal-lexical", "version_check", ] @@ -4982,9 +5031,9 @@ dependencies = [ [[package]] name = "object" -version = "0.26.2" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39f37e50073ccad23b6d09bcb5b263f4e76d3bb6038e4a3c08e52162ffa8abc2" +checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9" dependencies = [ "crc32fast", "indexmap", @@ -4997,6 +5046,12 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" +[[package]] +name = "oorandom" +version = "11.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" + [[package]] name = "opaque-debug" version = "0.2.3" @@ -5010,10 +5065,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] -name = "openssl-probe" -version = "0.1.2" +name = "open-metrics-client" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" +checksum = "7337d80c23c2d8b1349563981bc4fb531220733743ba8115454a67b181173f0d" +dependencies = [ + "dtoa", + "itoa", + "open-metrics-client-derive-text-encode", + "owning_ref", +] + +[[package]] +name = "open-metrics-client-derive-text-encode" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a15c83b586f00268c619c1cb3340ec1a6f59dd9ba1d9833a273a68e6d5cd8ffc" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-probe" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a" [[package]] name = "ordered-float" @@ -5035,30 +5113,25 @@ dependencies = [ [[package]] name = "pallet-asset-tx-payment" -version = "0.1.0" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#b03e8bcf151bbf4c20a7d7faa782366fc3554d58" dependencies = [ "frame-support", "frame-system", - "pallet-assets", - "pallet-authorship", - "pallet-balances", "pallet-transaction-payment", "parity-scale-codec", "scale-info", "serde", - "serde_json", - "smallvec", "sp-core", "sp-io", "sp-runtime", "sp-std", - "sp-storage", ] [[package]] name = "pallet-assets" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#b03e8bcf151bbf4c20a7d7faa782366fc3554d58" dependencies = [ "frame-benchmarking", "frame-support", @@ -5072,7 +5145,7 @@ dependencies = [ [[package]] name = "pallet-aura" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#b03e8bcf151bbf4c20a7d7faa782366fc3554d58" dependencies = [ "frame-support", "frame-system", @@ -5088,7 +5161,7 @@ dependencies = [ [[package]] name = "pallet-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "frame-support", "frame-system", @@ -5104,7 +5177,7 @@ dependencies = [ [[package]] name = "pallet-authorship" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "frame-support", "frame-system", @@ -5119,7 +5192,7 @@ dependencies = [ [[package]] name = "pallet-babe" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "frame-benchmarking", "frame-support", @@ -5143,7 +5216,7 @@ dependencies = [ [[package]] name = "pallet-bags-list" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -5163,7 +5236,7 @@ dependencies = [ [[package]] name = "pallet-balances" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "frame-benchmarking", "frame-support", @@ -5178,7 +5251,7 @@ dependencies = [ [[package]] name = "pallet-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "beefy-primitives", "frame-support", @@ -5194,14 +5267,14 @@ dependencies = [ [[package]] name = "pallet-beefy-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "beefy-merkle-tree", "beefy-primitives", "frame-support", "frame-system", "hex", - "libsecp256k1 0.7.0", + "libsecp256k1", "log", "pallet-beefy", "pallet-mmr", @@ -5219,7 +5292,7 @@ dependencies = [ [[package]] name = "pallet-bounties" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "frame-benchmarking", "frame-support", @@ -5237,7 +5310,7 @@ dependencies = [ [[package]] name = "pallet-bridge-dispatch" version = "0.1.0" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "bp-message-dispatch", "bp-runtime", @@ -5254,7 +5327,7 @@ dependencies = [ [[package]] name = "pallet-bridge-grandpa" version = "0.1.0" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "bp-header-chain", "bp-runtime", @@ -5276,12 +5349,11 @@ dependencies = [ [[package]] name = "pallet-bridge-messages" version = "0.1.0" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ - "bitvec 0.20.1", + "bitvec", "bp-message-dispatch", "bp-messages", - "bp-rialto", "bp-runtime", "frame-support", "frame-system", @@ -5324,7 +5396,7 @@ dependencies = [ [[package]] name = "pallet-collective" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "frame-benchmarking", "frame-support", @@ -5341,7 +5413,7 @@ dependencies = [ [[package]] name = "pallet-democracy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "frame-benchmarking", "frame-support", @@ -5357,7 +5429,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-multi-phase" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -5374,14 +5446,14 @@ dependencies = [ "sp-runtime", "sp-std", "static_assertions", - "strum 0.21.0", - "strum_macros 0.21.1", + "strum 0.22.0", + "strum_macros 0.23.1", ] [[package]] name = "pallet-elections-phragmen" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "frame-benchmarking", "frame-support", @@ -5399,7 +5471,7 @@ dependencies = [ [[package]] name = "pallet-gilt" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "frame-benchmarking", "frame-support", @@ -5414,7 +5486,7 @@ dependencies = [ [[package]] name = "pallet-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "frame-benchmarking", "frame-support", @@ -5437,7 +5509,7 @@ dependencies = [ [[package]] name = "pallet-identity" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "enumflags2", "frame-benchmarking", @@ -5453,7 +5525,7 @@ dependencies = [ [[package]] name = "pallet-im-online" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "frame-benchmarking", "frame-support", @@ -5473,7 +5545,7 @@ dependencies = [ [[package]] name = "pallet-indices" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "frame-benchmarking", "frame-support", @@ -5490,7 +5562,7 @@ dependencies = [ [[package]] name = "pallet-membership" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "frame-benchmarking", "frame-support", @@ -5507,7 +5579,7 @@ dependencies = [ [[package]] name = "pallet-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "ckb-merkle-mountain-range", "frame-benchmarking", @@ -5525,7 +5597,7 @@ dependencies = [ [[package]] name = "pallet-mmr-primitives" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "frame-support", "frame-system", @@ -5541,7 +5613,7 @@ dependencies = [ [[package]] name = "pallet-mmr-rpc" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "jsonrpc-core", "jsonrpc-core-client", @@ -5558,7 +5630,7 @@ dependencies = [ [[package]] name = "pallet-multisig" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "frame-benchmarking", "frame-support", @@ -5573,7 +5645,7 @@ dependencies = [ [[package]] name = "pallet-nicks" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "frame-support", "frame-system", @@ -5587,7 +5659,7 @@ dependencies = [ [[package]] name = "pallet-offences" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "frame-support", "frame-system", @@ -5604,7 +5676,7 @@ dependencies = [ [[package]] name = "pallet-offences-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -5624,10 +5696,26 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-preimage" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-proxy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "frame-benchmarking", "frame-support", @@ -5639,24 +5727,10 @@ dependencies = [ "sp-std", ] -[[package]] -name = "pallet-randomness-collective-flip" -version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" -dependencies = [ - "frame-support", - "frame-system", - "parity-scale-codec", - "safe-mix", - "scale-info", - "sp-runtime", - "sp-std", -] - [[package]] name = "pallet-recovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "frame-support", "frame-system", @@ -5670,7 +5744,7 @@ dependencies = [ [[package]] name = "pallet-scheduler" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "frame-benchmarking", "frame-support", @@ -5686,7 +5760,7 @@ dependencies = [ [[package]] name = "pallet-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "frame-support", "frame-system", @@ -5707,7 +5781,7 @@ dependencies = [ [[package]] name = "pallet-session-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "frame-benchmarking", "frame-support", @@ -5723,7 +5797,7 @@ dependencies = [ [[package]] name = "pallet-society" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "frame-support", "frame-system", @@ -5737,7 +5811,7 @@ dependencies = [ [[package]] name = "pallet-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -5760,7 +5834,7 @@ dependencies = [ [[package]] name = "pallet-staking-reward-curve" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "proc-macro-crate 1.1.0", "proc-macro2", @@ -5771,7 +5845,7 @@ dependencies = [ [[package]] name = "pallet-staking-reward-fn" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "log", "sp-arithmetic", @@ -5780,7 +5854,7 @@ dependencies = [ [[package]] name = "pallet-sudo" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "frame-support", "frame-system", @@ -5809,7 +5883,7 @@ dependencies = [ [[package]] name = "pallet-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "frame-benchmarking", "frame-support", @@ -5827,7 +5901,7 @@ dependencies = [ [[package]] name = "pallet-tips" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "frame-benchmarking", "frame-support", @@ -5846,7 +5920,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "frame-support", "frame-system", @@ -5863,7 +5937,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "jsonrpc-core", "jsonrpc-core-client", @@ -5880,7 +5954,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "pallet-transaction-payment", "parity-scale-codec", @@ -5891,7 +5965,7 @@ dependencies = [ [[package]] name = "pallet-treasury" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "frame-benchmarking", "frame-support", @@ -5908,11 +5982,12 @@ dependencies = [ [[package]] name = "pallet-uniques" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#66296a0af0aede07c27104e6174a3534b15f14aa" +source = "git+https://github.com/paritytech/substrate?branch=master#b03e8bcf151bbf4c20a7d7faa782366fc3554d58" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", + "log", "parity-scale-codec", "scale-info", "sp-runtime", @@ -5922,7 +5997,7 @@ dependencies = [ [[package]] name = "pallet-utility" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "frame-benchmarking", "frame-support", @@ -5938,7 +6013,7 @@ dependencies = [ [[package]] name = "pallet-vesting" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "frame-benchmarking", "frame-support", @@ -5952,8 +6027,8 @@ dependencies = [ [[package]] name = "pallet-xcm" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "frame-support", "frame-system", @@ -5971,7 +6046,7 @@ dependencies = [ [[package]] name = "pallet-xcm-benchmarks" version = "0.9.8" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "frame-benchmarking", "frame-support", @@ -6009,10 +6084,12 @@ dependencies = [ "cumulus-client-service", "cumulus-primitives-core", "cumulus-primitives-parachain-inherent", + "cumulus-relay-chain-interface", + "cumulus-relay-chain-local", "derive_more", "frame-benchmarking", "frame-benchmarking-cli", - "hex-literal 0.3.3", + "hex-literal 0.3.4", "jsonrpc-core", "log", "pallet-transaction-payment-rpc", @@ -6022,7 +6099,6 @@ dependencies = [ "polkadot-parachain", "polkadot-primitives", "polkadot-service", - "polkadot-test-service", "sc-basic-authorship", "sc-chain-spec", "sc-cli", @@ -6056,6 +6132,7 @@ dependencies = [ "substrate-build-script-utils", "substrate-frame-rpc-system", "substrate-prometheus-endpoint", + "try-runtime-cli", ] [[package]] @@ -6065,6 +6142,7 @@ dependencies = [ "cumulus-pallet-aura-ext", "cumulus-pallet-dmp-queue", "cumulus-pallet-parachain-system", + "cumulus-pallet-session-benchmarking", "cumulus-pallet-xcm", "cumulus-pallet-xcmp-queue", "cumulus-primitives-core", @@ -6076,12 +6154,13 @@ dependencies = [ "frame-system", "frame-system-benchmarking", "frame-system-rpc-runtime-api", + "frame-try-runtime", + "hex-literal 0.3.4", "log", "pallet-aura", "pallet-authorship", "pallet-balances", "pallet-collator-selection", - "pallet-randomness-collective-flip", "pallet-session", "pallet-sudo", "pallet-template", @@ -6142,9 +6221,9 @@ dependencies = [ [[package]] name = "parity-db" -version = "0.3.2" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91b679c6acc14fac74382942e2b73bea441686a33430b951ea03b5aeb6a7f254" +checksum = "78a95abf24f1097c6e3181abbbbfc3630b3b5e681470940f719b69acb4911c7f" dependencies = [ "blake2-rfc", "crc32fast", @@ -6153,8 +6232,8 @@ dependencies = [ "libc", "log", "lz4", - "memmap2", - "parking_lot 0.11.1", + "memmap2 0.2.3", + "parking_lot 0.11.2", "rand 0.8.4", "snap", ] @@ -6165,8 +6244,8 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "373b1a4c1338d9cd3d1fa53b3a11bdab5ab6bd80a20f7f7becd76953ae2be909" dependencies = [ - "arrayvec 0.7.0", - "bitvec 0.20.1", + "arrayvec 0.7.2", + "bitvec", "byte-slice-cast", "impl-trait-for-tuples", "parity-scale-codec-derive", @@ -6197,7 +6276,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9981e32fb75e004cc148f5fb70342f393830e0a4aa62e3cc93b50976218d42b6" dependencies = [ - "futures 0.3.17", + "futures 0.3.19", "libc", "log", "rand 0.7.3", @@ -6217,7 +6296,7 @@ dependencies = [ "impl-trait-for-tuples", "lru 0.6.6", "parity-util-mem-derive", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "primitive-types", "smallvec", "winapi 0.3.9", @@ -6251,9 +6330,9 @@ checksum = "be5e13c266502aadf83426d87d81a0f5d1ef45b8027f5a471c360abfe4bfae92" [[package]] name = "parity-ws" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0ab8a461779bd022964cae2b4989fa9c99deb270bec162da2125ec03c09fcaa" +checksum = "5983d3929ad50f12c3eb9a6743f19d691866ecd44da74c0a3308c3f8a56df0c6" dependencies = [ "byteorder", "bytes 0.4.12", @@ -6264,7 +6343,7 @@ dependencies = [ "rand 0.7.3", "sha-1 0.8.2", "slab", - "url 2.2.0", + "url 2.2.2", ] [[package]] @@ -6285,13 +6364,13 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" dependencies = [ "instant", - "lock_api 0.4.2", - "parking_lot_core 0.8.2", + "lock_api 0.4.5", + "parking_lot_core 0.8.5", ] [[package]] @@ -6310,33 +6389,23 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.8.2" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ccb628cad4f84851442432c60ad8e1f607e29752d0bf072cbd0baf28aa34272" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" dependencies = [ "cfg-if 1.0.0", "instant", "libc", - "redox_syscall 0.1.57", + "redox_syscall 0.2.10", "smallvec", "winapi 0.3.9", ] [[package]] name = "paste" -version = "1.0.4" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5d65c4d95931acda4498f675e332fcbdc9a06705cd07086c510e9b6009cd1c1" - -[[package]] -name = "pbkdf2" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "006c038a43a45995a9670da19e67600114740e8511d4333bf97a56e66a7542d9" -dependencies = [ - "byteorder", - "crypto-mac 0.7.0", -] +checksum = "0744126afe1a6dd7f394cb50a716dbe086cb06e255e53d8d0185d82828358fb5" [[package]] name = "pbkdf2" @@ -6347,6 +6416,15 @@ dependencies = [ "crypto-mac 0.8.0", ] +[[package]] +name = "pbkdf2" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d95f5254224e617595d2cc3cc73ff0a5eaf2637519e25f03388154e9378b6ffa" +dependencies = [ + "crypto-mac 0.11.1", +] + [[package]] name = "peeking_take_while" version = "0.1.2" @@ -6410,9 +6488,9 @@ dependencies = [ [[package]] name = "petgraph" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7" +checksum = "4a13a2fa9d0b63e5f22328828741e523766fff0ee9e779316902290dff3f824f" dependencies = [ "fixedbitset", "indexmap", @@ -6420,11 +6498,11 @@ dependencies = [ [[package]] name = "pin-project" -version = "0.4.27" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffbc8e94b38ea3d2d8ba92aea2983b503cd75d0888d75b86bb37970b5698e15" +checksum = "918192b5c59119d51e0cd221f4d49dde9112824ba717369e903c97d076083d0f" dependencies = [ - "pin-project-internal 0.4.27", + "pin-project-internal 0.4.28", ] [[package]] @@ -6438,9 +6516,9 @@ dependencies = [ [[package]] name = "pin-project-internal" -version = "0.4.27" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65ad2ae56b6abe3a1ee25f15ee605bacadb9a764edaba9c2bf4103800d4a1895" +checksum = "3be26700300be6d9d23264c73211d8190e755b6b5ca7a1b28230025511b52a5e" dependencies = [ "proc-macro2", "quote", @@ -6460,15 +6538,15 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c917123afa01924fc84bb20c4c03f004d9c38e5127e3c039bbf7f4b9c76a2f6b" +checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777" [[package]] name = "pin-project-lite" -version = "0.2.4" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439697af366c49a6d0a010c56a0d97685bc140ce0d377b13a2ea2aa42d64a827" +checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" [[package]] name = "pin-utils" @@ -6478,22 +6556,50 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.19" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" +checksum = "12295df4f294471248581bc09bef3c38a5e46f1e36d6a37353621a0c6c357e1f" [[package]] name = "platforms" -version = "1.1.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "989d43012e2ca1c4a02507c67282691a0a3207f9dc67cec596b43fe925b3d325" +checksum = "e8d0eef3571242013a0d5dc84861c3ae4a652e56e12adf8bdc26ff5f8cb34c94" + +[[package]] +name = "plotters" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a3fd9ec30b9749ce28cd91f255d569591cdf937fe280c312143e3c4bad6f2a" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d88417318da0eaf0fdcdb51a0ee6c3bed624333bff8f946733049380be67ac1c" + +[[package]] +name = "plotters-svg" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521fa9638fa597e1dc53e9412a4f9cefb01187ee1f7413076f9e6749e2885ba9" +dependencies = [ + "plotters-backend", +] [[package]] name = "polkadot-approval-distribution" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ - "futures 0.3.17", + "futures 0.3.19", "polkadot-node-network-protocol", "polkadot-node-primitives", "polkadot-node-subsystem", @@ -6504,10 +6610,10 @@ dependencies = [ [[package]] name = "polkadot-availability-bitfield-distribution" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ - "futures 0.3.17", + "futures 0.3.19", "polkadot-node-network-protocol", "polkadot-node-subsystem", "polkadot-node-subsystem-util", @@ -6517,12 +6623,12 @@ dependencies = [ [[package]] name = "polkadot-availability-distribution" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "derive_more", - "futures 0.3.17", - "lru 0.7.0", + "futures 0.3.19", + "lru 0.7.1", "parity-scale-codec", "polkadot-erasure-coding", "polkadot-node-network-protocol", @@ -6539,11 +6645,11 @@ dependencies = [ [[package]] name = "polkadot-availability-recovery" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ - "futures 0.3.17", - "lru 0.7.0", + "futures 0.3.19", + "lru 0.7.1", "parity-scale-codec", "polkadot-erasure-coding", "polkadot-node-network-protocol", @@ -6559,16 +6665,19 @@ dependencies = [ [[package]] name = "polkadot-cli" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "frame-benchmarking-cli", - "futures 0.3.17", + "futures 0.3.19", "log", "polkadot-node-core-pvf", + "polkadot-node-metrics", + "polkadot-performance-test", "polkadot-service", "sc-cli", "sc-service", + "sc-tracing", "sp-core", "sp-trie", "structopt", @@ -6579,8 +6688,8 @@ dependencies = [ [[package]] name = "polkadot-client" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "beefy-primitives", "frame-benchmarking", @@ -6609,7 +6718,7 @@ dependencies = [ [[package]] name = "polkadot-collator" -version = "4.0.0" +version = "5.0.0" dependencies = [ "assert_cmd", "async-trait", @@ -6621,9 +6730,11 @@ dependencies = [ "cumulus-client-service", "cumulus-primitives-core", "cumulus-primitives-parachain-inherent", + "cumulus-relay-chain-interface", + "cumulus-relay-chain-local", "frame-benchmarking", "frame-benchmarking-cli", - "futures 0.3.17", + "futures 0.3.19", "hex-literal 0.2.1", "jsonrpc-core", "log", @@ -6635,7 +6746,7 @@ dependencies = [ "polkadot-parachain", "polkadot-primitives", "polkadot-service", - "rococo-runtime 0.1.0", + "rococo-parachain-runtime", "sc-basic-authorship", "sc-chain-spec", "sc-cli", @@ -6649,6 +6760,7 @@ dependencies = [ "sc-tracing", "sc-transaction-pool", "sc-transaction-pool-api", + "seedling-runtime", "serde", "shell-runtime", "sp-api", @@ -6672,17 +6784,18 @@ dependencies = [ "substrate-frame-rpc-system", "substrate-prometheus-endpoint", "tempfile", + "try-runtime-cli", "westmint-runtime", ] [[package]] name = "polkadot-collator-protocol" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "always-assert", "derive_more", - "futures 0.3.17", + "futures 0.3.19", "futures-timer 3.0.2", "polkadot-node-network-protocol", "polkadot-node-primitives", @@ -6698,8 +6811,8 @@ dependencies = [ [[package]] name = "polkadot-core-primitives" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "parity-scale-codec", "parity-util-mem", @@ -6711,12 +6824,12 @@ dependencies = [ [[package]] name = "polkadot-dispute-distribution" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "derive_more", - "futures 0.3.17", - "lru 0.7.0", + "futures 0.3.19", + "lru 0.7.1", "parity-scale-codec", "polkadot-erasure-coding", "polkadot-node-network-protocol", @@ -6733,8 +6846,8 @@ dependencies = [ [[package]] name = "polkadot-erasure-coding" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "parity-scale-codec", "polkadot-node-primitives", @@ -6747,10 +6860,10 @@ dependencies = [ [[package]] name = "polkadot-gossip-support" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ - "futures 0.3.17", + "futures 0.3.19", "futures-timer 3.0.2", "polkadot-node-network-protocol", "polkadot-node-subsystem", @@ -6767,13 +6880,13 @@ dependencies = [ [[package]] name = "polkadot-network-bridge" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "async-trait", - "futures 0.3.17", + "futures 0.3.19", "parity-scale-codec", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "polkadot-node-network-protocol", "polkadot-node-subsystem", "polkadot-node-subsystem-util", @@ -6786,10 +6899,10 @@ dependencies = [ [[package]] name = "polkadot-node-collation-generation" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ - "futures 0.3.17", + "futures 0.3.19", "parity-scale-codec", "polkadot-erasure-coding", "polkadot-node-primitives", @@ -6804,15 +6917,15 @@ dependencies = [ [[package]] name = "polkadot-node-core-approval-voting" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ - "bitvec 0.20.1", + "bitvec", "derive_more", - "futures 0.3.17", + "futures 0.3.19", "futures-timer 3.0.2", "kvdb", - "lru 0.7.0", + "lru 0.7.1", "merlin", "parity-scale-codec", "polkadot-node-jaeger", @@ -6832,11 +6945,11 @@ dependencies = [ [[package]] name = "polkadot-node-core-av-store" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ - "bitvec 0.20.1", - "futures 0.3.17", + "bitvec", + "futures 0.3.19", "futures-timer 3.0.2", "kvdb", "parity-scale-codec", @@ -6852,11 +6965,11 @@ dependencies = [ [[package]] name = "polkadot-node-core-backing" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ - "bitvec 0.20.1", - "futures 0.3.17", + "bitvec", + "futures 0.3.19", "polkadot-erasure-coding", "polkadot-node-primitives", "polkadot-node-subsystem", @@ -6870,10 +6983,10 @@ dependencies = [ [[package]] name = "polkadot-node-core-bitfield-signing" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ - "futures 0.3.17", + "futures 0.3.19", "polkadot-node-subsystem", "polkadot-node-subsystem-util", "polkadot-primitives", @@ -6885,11 +6998,11 @@ dependencies = [ [[package]] name = "polkadot-node-core-candidate-validation" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "async-trait", - "futures 0.3.17", + "futures 0.3.19", "parity-scale-codec", "polkadot-node-core-pvf", "polkadot-node-primitives", @@ -6903,10 +7016,10 @@ dependencies = [ [[package]] name = "polkadot-node-core-chain-api" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ - "futures 0.3.17", + "futures 0.3.19", "polkadot-node-subsystem", "polkadot-node-subsystem-util", "polkadot-primitives", @@ -6918,10 +7031,10 @@ dependencies = [ [[package]] name = "polkadot-node-core-chain-selection" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ - "futures 0.3.17", + "futures 0.3.19", "futures-timer 3.0.2", "kvdb", "parity-scale-codec", @@ -6935,13 +7048,12 @@ dependencies = [ [[package]] name = "polkadot-node-core-dispute-coordinator" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ - "bitvec 0.20.1", - "derive_more", - "futures 0.3.17", + "futures 0.3.19", "kvdb", + "lru 0.7.1", "parity-scale-codec", "polkadot-node-primitives", "polkadot-node-subsystem", @@ -6952,26 +7064,13 @@ dependencies = [ "tracing", ] -[[package]] -name = "polkadot-node-core-dispute-participation" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" -dependencies = [ - "futures 0.3.17", - "polkadot-node-primitives", - "polkadot-node-subsystem", - "polkadot-primitives", - "thiserror", - "tracing", -] - [[package]] name = "polkadot-node-core-parachains-inherent" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "async-trait", - "futures 0.3.17", + "futures 0.3.19", "futures-timer 3.0.2", "polkadot-node-subsystem", "polkadot-primitives", @@ -6984,31 +7083,32 @@ dependencies = [ [[package]] name = "polkadot-node-core-provisioner" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ - "bitvec 0.20.1", - "futures 0.3.17", + "bitvec", + "futures 0.3.19", "futures-timer 3.0.2", + "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-node-subsystem-util", "polkadot-primitives", + "rand 0.8.4", "thiserror", "tracing", ] [[package]] name = "polkadot-node-core-pvf" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "always-assert", "assert_matches", "async-process", "async-std", - "futures 0.3.17", + "futures 0.3.19", "futures-timer 3.0.2", - "libc", "parity-scale-codec", "pin-project 1.0.8", "polkadot-core-primitives", @@ -7030,10 +7130,10 @@ dependencies = [ [[package]] name = "polkadot-node-core-runtime-api" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ - "futures 0.3.17", + "futures 0.3.19", "memory-lru", "parity-util-mem", "polkadot-node-subsystem", @@ -7048,15 +7148,15 @@ dependencies = [ [[package]] name = "polkadot-node-jaeger" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "async-std", "lazy_static", "log", "mick-jaeger", "parity-scale-codec", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "polkadot-node-primitives", "polkadot-primitives", "sc-network", @@ -7066,40 +7166,48 @@ dependencies = [ [[package]] name = "polkadot-node-metrics" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ - "futures 0.3.17", + "bs58", + "futures 0.3.19", "futures-timer 3.0.2", + "log", "metered-channel", + "parity-scale-codec", + "polkadot-primitives", + "sc-cli", + "sc-service", + "sc-tracing", "substrate-prometheus-endpoint", + "tracing", ] [[package]] name = "polkadot-node-network-protocol" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "async-trait", "derive_more", - "futures 0.3.17", + "futures 0.3.19", "parity-scale-codec", "polkadot-node-jaeger", "polkadot-node-primitives", "polkadot-primitives", "sc-authority-discovery", "sc-network", - "strum 0.22.0", + "strum 0.23.0", "thiserror", ] [[package]] name = "polkadot-node-primitives" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "bounded-vec", - "futures 0.3.17", + "futures 0.3.19", "parity-scale-codec", "polkadot-parachain", "polkadot-primitives", @@ -7117,8 +7225,8 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "polkadot-node-jaeger", "polkadot-node-subsystem-types", @@ -7127,12 +7235,12 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem-test-helpers" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "async-trait", - "futures 0.3.17", - "parking_lot 0.11.1", + "futures 0.3.19", + "parking_lot 0.11.2", "polkadot-node-subsystem", "polkadot-node-subsystem-util", "polkadot-primitives", @@ -7145,11 +7253,11 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem-types" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "derive_more", - "futures 0.3.17", + "futures 0.3.19", "polkadot-node-jaeger", "polkadot-node-network-protocol", "polkadot-node-primitives", @@ -7164,20 +7272,21 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem-util" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "async-trait", "derive_more", - "futures 0.3.17", + "futures 0.3.19", "itertools", - "lru 0.7.0", + "lru 0.7.1", "metered-channel", "parity-scale-codec", "pin-project 1.0.8", "polkadot-node-jaeger", "polkadot-node-metrics", "polkadot-node-network-protocol", + "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-overseer", "polkadot-primitives", @@ -7191,14 +7300,14 @@ dependencies = [ [[package]] name = "polkadot-overseer" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ - "futures 0.3.17", + "futures 0.3.19", "futures-timer 3.0.2", - "lru 0.7.0", + "lru 0.7.1", "parity-util-mem", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "polkadot-node-metrics", "polkadot-node-network-protocol", "polkadot-node-primitives", @@ -7212,11 +7321,11 @@ dependencies = [ [[package]] name = "polkadot-overseer-gen" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "async-trait", - "futures 0.3.17", + "futures 0.3.19", "futures-timer 3.0.2", "metered-channel", "pin-project 1.0.8", @@ -7229,8 +7338,8 @@ dependencies = [ [[package]] name = "polkadot-overseer-gen-proc-macro" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "proc-macro-crate 1.1.0", "proc-macro2", @@ -7240,8 +7349,8 @@ dependencies = [ [[package]] name = "polkadot-parachain" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "derive_more", "frame-support", @@ -7256,13 +7365,28 @@ dependencies = [ ] [[package]] -name = "polkadot-primitives" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +name = "polkadot-performance-test" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ - "bitvec 0.20.1", + "env_logger 0.9.0", + "kusama-runtime", + "log", + "polkadot-erasure-coding", + "polkadot-node-core-pvf", + "polkadot-node-primitives", + "quote", + "thiserror", +] + +[[package]] +name = "polkadot-primitives" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" +dependencies = [ + "bitvec", "frame-system", - "hex-literal 0.3.3", + "hex-literal 0.3.4", "parity-scale-codec", "parity-util-mem", "polkadot-core-primitives", @@ -7287,8 +7411,8 @@ dependencies = [ [[package]] name = "polkadot-rpc" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "beefy-gadget", "beefy-gadget-rpc", @@ -7318,11 +7442,11 @@ dependencies = [ [[package]] name = "polkadot-runtime" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "beefy-primitives", - "bitvec 0.20.1", + "bitvec", "frame-benchmarking", "frame-election-provider-support", "frame-executive", @@ -7331,11 +7455,12 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal 0.3.3", + "hex-literal 0.3.4", "log", "pallet-authority-discovery", "pallet-authorship", "pallet-babe", + "pallet-bags-list", "pallet-balances", "pallet-bounties", "pallet-collective", @@ -7352,6 +7477,7 @@ dependencies = [ "pallet-nicks", "pallet-offences", "pallet-offences-benchmarking", + "pallet-preimage", "pallet-proxy", "pallet-scheduler", "pallet-session", @@ -7365,9 +7491,11 @@ dependencies = [ "pallet-treasury", "pallet-utility", "pallet-vesting", + "pallet-xcm", "parity-scale-codec", "polkadot-primitives", "polkadot-runtime-common", + "polkadot-runtime-constants", "polkadot-runtime-parachains", "rustc-hex", "scale-info", @@ -7391,21 +7519,24 @@ dependencies = [ "sp-version", "static_assertions", "substrate-wasm-builder", + "xcm", + "xcm-builder", + "xcm-executor", ] [[package]] name = "polkadot-runtime-common" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "beefy-primitives", - "bitvec 0.20.1", + "bitvec", "frame-benchmarking", "frame-election-provider-support", "frame-support", "frame-system", "impl-trait-for-tuples", - "libsecp256k1 0.7.0", + "libsecp256k1", "log", "pallet-authorship", "pallet-babe", @@ -7440,13 +7571,37 @@ dependencies = [ "xcm", ] +[[package]] +name = "polkadot-runtime-constants" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" +dependencies = [ + "frame-support", + "polkadot-primitives", + "polkadot-runtime-common", + "smallvec", + "sp-runtime", +] + +[[package]] +name = "polkadot-runtime-metrics" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" +dependencies = [ + "bs58", + "parity-scale-codec", + "polkadot-primitives", + "sp-std", + "sp-tracing", +] + [[package]] name = "polkadot-runtime-parachains" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "bitflags", - "bitvec 0.20.1", + "bitvec", "derive_more", "frame-benchmarking", "frame-support", @@ -7454,6 +7609,7 @@ dependencies = [ "log", "pallet-authority-discovery", "pallet-authorship", + "pallet-babe", "pallet-balances", "pallet-session", "pallet-staking", @@ -7461,6 +7617,7 @@ dependencies = [ "pallet-vesting", "parity-scale-codec", "polkadot-primitives", + "polkadot-runtime-metrics", "rand 0.8.4", "rand_chacha 0.3.1", "rustc-hex", @@ -7481,19 +7638,19 @@ dependencies = [ [[package]] name = "polkadot-service" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "async-trait", "beefy-gadget", "beefy-primitives", "frame-system-rpc-runtime-api", - "futures 0.3.17", - "hex-literal 0.3.3", + "futures 0.3.19", + "hex-literal 0.3.4", "kusama-runtime", "kvdb", "kvdb-rocksdb", - "lru 0.7.0", + "lru 0.7.1", "pallet-babe", "pallet-im-online", "pallet-mmr-primitives", @@ -7517,7 +7674,6 @@ dependencies = [ "polkadot-node-core-chain-api", "polkadot-node-core-chain-selection", "polkadot-node-core-dispute-coordinator", - "polkadot-node-core-dispute-participation", "polkadot-node-core-parachains-inherent", "polkadot-node-core-provisioner", "polkadot-node-core-runtime-api", @@ -7530,9 +7686,10 @@ dependencies = [ "polkadot-primitives", "polkadot-rpc", "polkadot-runtime", + "polkadot-runtime-constants", "polkadot-runtime-parachains", "polkadot-statement-distribution", - "rococo-runtime 0.9.12", + "rococo-runtime", "sc-authority-discovery", "sc-basic-authorship", "sc-block-builder", @@ -7547,6 +7704,7 @@ dependencies = [ "sc-finality-grandpa", "sc-keystore", "sc-network", + "sc-offchain", "sc-service", "sc-sync-state-rpc", "sc-telemetry", @@ -7579,12 +7737,12 @@ dependencies = [ [[package]] name = "polkadot-statement-distribution" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "arrayvec 0.5.2", "derive_more", - "futures 0.3.17", + "futures 0.3.19", "indexmap", "parity-scale-codec", "polkadot-node-network-protocol", @@ -7600,8 +7758,8 @@ dependencies = [ [[package]] name = "polkadot-statement-table" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "parity-scale-codec", "polkadot-primitives", @@ -7610,8 +7768,8 @@ dependencies = [ [[package]] name = "polkadot-test-client" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "parity-scale-codec", "polkadot-node-subsystem", @@ -7635,11 +7793,11 @@ dependencies = [ [[package]] name = "polkadot-test-runtime" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "beefy-primitives", - "bitvec 0.20.1", + "bitvec", "frame-election-provider-support", "frame-executive", "frame-support", @@ -7689,6 +7847,7 @@ dependencies = [ "sp-transaction-pool", "sp-version", "substrate-wasm-builder", + "test-runtime-constants", "xcm", "xcm-builder", "xcm-executor", @@ -7696,13 +7855,13 @@ dependencies = [ [[package]] name = "polkadot-test-service" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "frame-benchmarking", "frame-system", - "futures 0.1.30", - "futures 0.3.17", + "futures 0.1.31", + "futures 0.3.19", "hex", "pallet-balances", "pallet-staking", @@ -7743,57 +7902,58 @@ dependencies = [ "sp-state-machine", "substrate-test-client", "tempfile", + "test-runtime-constants", "tokio", "tracing", ] [[package]] name = "polling" -version = "2.0.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2a7bc6b2a29e632e45451c941832803a18cce6781db04de8a04696cdca8bde4" +checksum = "685404d509889fade3e86fe3a5803bca2ec09b0c0778d5ada6ec8bf7a8de5259" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", "libc", "log", - "wepoll-sys", + "wepoll-ffi", "winapi 0.3.9", ] [[package]] name = "poly1305" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fcffab1f78ebbdf4b93b68c1ffebc24037eedf271edaca795732b24e5e4e349" +checksum = "048aeb476be11a4b6ca432ca569e375810de9294ae78f4774e78ea98a9246ede" dependencies = [ - "cpufeatures 0.1.5", + "cpufeatures 0.2.1", "opaque-debug 0.3.0", "universal-hash", ] [[package]] name = "polyval" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6ba6a405ef63530d6cb12802014b22f9c5751bd17cdcddbe9e46d5c8ae83287" +checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" dependencies = [ "cfg-if 1.0.0", - "cpufeatures 0.1.5", + "cpufeatures 0.2.1", "opaque-debug 0.3.0", "universal-hash", ] [[package]] name = "ppv-lite86" -version = "0.2.10" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" +checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba" [[package]] name = "predicates" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73dd9b7b200044694dfede9edf907c1ca19630908443e9447e624993700c6932" +checksum = "f49cfaf7fdaa3bfacc6fa3e7054e65148878354a5cfddcf661df4c851f8021df" dependencies = [ "difference", "predicates-core", @@ -7801,18 +7961,18 @@ dependencies = [ [[package]] name = "predicates-core" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb3dbeaaf793584e29c58c7e3a82bbb3c7c06b63cea68d13b0e3cddc124104dc" +checksum = "57e35a3326b75e49aa85f5dc6ec15b41108cf5aee58eabb1f274dd18b73c2451" [[package]] name = "predicates-tree" -version = "1.0.1" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aee95d988ee893cb35c06b148c80ed2cd52c8eea927f50ba7a0be1a786aeab73" +checksum = "338c7be2905b732ae3984a2f40032b5e94fd8f52505b186c7d4d68d193445df7" dependencies = [ "predicates-core", - "treeline", + "termtree", ] [[package]] @@ -7848,45 +8008,19 @@ dependencies = [ "toml", ] -[[package]] -name = "proc-macro-error" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18f33027081eba0a6d8aba6d1b1c3a3be58cbb12106341c2d5759fcd9b5277e7" -dependencies = [ - "proc-macro-error-attr 0.4.12", - "proc-macro2", - "quote", - "syn", - "version_check", -] - [[package]] name = "proc-macro-error" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ - "proc-macro-error-attr 1.0.4", + "proc-macro-error-attr", "proc-macro2", "quote", "syn", "version_check", ] -[[package]] -name = "proc-macro-error-attr" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a5b4b77fdb63c1eca72173d68d24501c54ab1269409f6b672c85deb18af69de" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "syn-mid", - "version_check", -] - [[package]] name = "proc-macro-error-attr" version = "1.0.4" @@ -7904,68 +8038,64 @@ version = "0.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" -[[package]] -name = "proc-macro-nested" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eba180dafb9038b050a4c280019bbedf9f2467b61e5d892dcad585bb57aadc5a" - [[package]] name = "proc-macro2" -version = "1.0.30" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edc3358ebc67bc8b7fa0c007f945b0b18226f78437d61bec735a9eb96b61ee70" +checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" dependencies = [ "unicode-xid", ] [[package]] name = "prometheus" -version = "0.12.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5986aa8d62380092d2f50f8b1cdba9cb9b6731ffd4b25b51fd126b6c3e05b99c" +checksum = "b7f64969ffd5dd8f39bd57a68ac53c163a095ed9d0fb707146da1b27025a3504" dependencies = [ "cfg-if 1.0.0", "fnv", "lazy_static", "memchr", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "thiserror", ] [[package]] name = "prost" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de5e2533f59d08fcf364fd374ebda0692a70bd6d7e66ef97f306f45c6c5d8020" +checksum = "444879275cb4fd84958b1a1d5420d15e6fcf7c235fe47f053c9c2a80aceb6001" dependencies = [ - "bytes 1.0.1", + "bytes 1.1.0", "prost-derive", ] [[package]] name = "prost-build" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "355f634b43cdd80724ee7848f95770e7e70eefa6dcf14fea676216573b8fd603" +checksum = "62941722fb675d463659e49c4f3fe1fe792ff24fe5bbaa9c08cd3b98a1c354f5" dependencies = [ - "bytes 1.0.1", + "bytes 1.1.0", "heck", "itertools", + "lazy_static", "log", "multimap", "petgraph", "prost", "prost-types", + "regex", "tempfile", "which", ] [[package]] name = "prost-derive" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "600d2f334aa05acb02a755e217ef1ab6dea4d51b58b7846588b747edec04efba" +checksum = "f9cc1a3263e07e0bf68e96268f37665207b49560d98739662cdfaae215c720fe" dependencies = [ "anyhow", "itertools", @@ -7976,28 +8106,28 @@ dependencies = [ [[package]] name = "prost-types" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "603bbd6394701d13f3f25aada59c7de9d35a6a5887cfc156181234a44002771b" +checksum = "534b7a0e836e3c482d2693070f982e39e7611da9695d4d1f5a4b186b51faef0a" dependencies = [ - "bytes 1.0.1", + "bytes 1.1.0", "prost", ] [[package]] name = "psm" -version = "0.1.12" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3abf49e5417290756acfd26501536358560c4a5cc4a0934d390939acb3e7083a" +checksum = "cd136ff4382c4753fc061cb9e4712ab2af263376b95bbd5bd8cd50c020b78e69" dependencies = [ "cc", ] [[package]] name = "pwasm-utils" -version = "0.18.0" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0e517f47d9964362883182404b68d0b6949382c0baa40aa5ffca94f5f1e3481" +checksum = "880b3384fb00b8f6ecccd5d358b93bd2201900ae3daad213791d1864f6441f5c" dependencies = [ "byteorder", "log", @@ -8012,9 +8142,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quick-error" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ac73b1112776fc109b2e61909bc46c7e1bf0d7f690ffb1676553acce16d5cda" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" [[package]] name = "quicksink" @@ -8024,7 +8154,7 @@ checksum = "77de3c815e5a160b1539c6592796801df2043ae35e123b46d73380cfa57af858" dependencies = [ "futures-core", "futures-sink", - "pin-project-lite 0.1.11", + "pin-project-lite 0.1.12", ] [[package]] @@ -8036,12 +8166,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "radium" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8" - [[package]] name = "radium" version = "0.6.2" @@ -8070,8 +8194,8 @@ checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" dependencies = [ "libc", "rand_chacha 0.3.1", - "rand_core 0.6.1", - "rand_hc 0.3.0", + "rand_core 0.6.3", + "rand_hc 0.3.1", ] [[package]] @@ -8091,7 +8215,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.1", + "rand_core 0.6.3", ] [[package]] @@ -8105,18 +8229,18 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c026d7df8b298d90ccbbc5190bd04d85e159eaf5576caeacf8741da93ccbd2e5" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" dependencies = [ - "getrandom 0.2.1", + "getrandom 0.2.3", ] [[package]] name = "rand_distr" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "051b398806e42b9cd04ad9ec8f81e355d0a382c543ac6672c62f5a5b452ef142" +checksum = "964d548f8e7d12e102ef183a0de7e98180c9f8729f555897a857b96e48122d2f" dependencies = [ "num-traits", "rand 0.8.4", @@ -8133,11 +8257,11 @@ dependencies = [ [[package]] name = "rand_hc" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" +checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" dependencies = [ - "rand_core 0.6.1", + "rand_core 0.6.3", ] [[package]] @@ -8157,9 +8281,9 @@ checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" [[package]] name = "rayon" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b0d8e0819fadc20c74ea8373106ead0600e3a67ef1fe8da56e39b9ae7275674" +checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" dependencies = [ "autocfg", "crossbeam-deque", @@ -8169,9 +8293,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.9.0" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a" +checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" dependencies = [ "crossbeam-channel", "crossbeam-deque", @@ -8188,9 +8312,9 @@ checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" [[package]] name = "redox_syscall" -version = "0.2.4" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ec8ca9416c5ea37062b502703cd7fcb207736bc294f6e0cf367ac6fc234570" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" dependencies = [ "bitflags", ] @@ -8201,8 +8325,8 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" dependencies = [ - "getrandom 0.2.1", - "redox_syscall 0.2.4", + "getrandom 0.2.3", + "redox_syscall 0.2.10", ] [[package]] @@ -8240,9 +8364,9 @@ dependencies = [ [[package]] name = "regalloc" -version = "0.0.31" +version = "0.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "571f7f397d61c4755285cd37853fe8e03271c243424a907415909379659381c5" +checksum = "a6304468554ed921da3d32c355ea107b8d13d7b8996c3adfb7aab48d3bc321f4" dependencies = [ "log", "rustc-hash", @@ -8262,11 +8386,10 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1ded71d66a4a97f5e961fd0cb25a5f366a42a41570d16a763a69c092c26ae4" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" dependencies = [ - "byteorder", "regex-syntax", ] @@ -8291,11 +8414,10 @@ dependencies = [ [[package]] name = "remote-externalities" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "env_logger 0.9.0", - "jsonrpsee-proc-macros", - "jsonrpsee-ws-client", + "jsonrpsee", "log", "parity-scale-codec", "serde", @@ -8327,15 +8449,15 @@ dependencies = [ [[package]] name = "retain_mut" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "448296241d034b96c11173591deaa1302f2c17b56092106c1f92c1bc0183a8c9" +checksum = "11000e6ba5020e53e7cc26f73b91ae7d5496b4977851479edb66b694c0675c21" [[package]] name = "ring" -version = "0.16.19" +version = "0.16.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "024a1e66fea74c66c66624ee5622a7ff0e4b73a13b4f5c326ddb50c708944226" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" dependencies = [ "cc", "libc", @@ -8348,11 +8470,11 @@ dependencies = [ [[package]] name = "rlp" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e54369147e3e7796c9b885c7304db87ca3d09a0a98f72843d532868675bbfba8" +checksum = "999508abb0ae792aabed2460c45b89106d97fe4adac593bdaef433c2605847b5" dependencies = [ - "bytes 1.0.1", + "bytes 1.1.0", "rustc-hex", ] @@ -8367,7 +8489,7 @@ dependencies = [ ] [[package]] -name = "rococo-runtime" +name = "rococo-parachain-runtime" version = "0.1.0" dependencies = [ "cumulus-pallet-aura-ext", @@ -8387,7 +8509,6 @@ dependencies = [ "pallet-assets", "pallet-aura", "pallet-balances", - "pallet-randomness-collective-flip", "pallet-sudo", "pallet-timestamp", "pallet-transaction-payment", @@ -8419,8 +8540,8 @@ dependencies = [ [[package]] name = "rococo-runtime" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "beefy-primitives", "bp-messages", @@ -8433,7 +8554,7 @@ dependencies = [ "frame-support", "frame-system", "frame-system-rpc-runtime-api", - "hex-literal 0.3.3", + "hex-literal 0.3.4", "log", "pallet-authority-discovery", "pallet-authorship", @@ -8467,6 +8588,7 @@ dependencies = [ "polkadot-primitives", "polkadot-runtime-common", "polkadot-runtime-parachains", + "rococo-runtime-constants", "scale-info", "serde", "serde_derive", @@ -8491,21 +8613,50 @@ dependencies = [ "xcm-executor", ] +[[package]] +name = "rococo-runtime-constants" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" +dependencies = [ + "frame-support", + "polkadot-primitives", + "polkadot-runtime-common", + "smallvec", + "sp-runtime", +] + [[package]] name = "rpassword" -version = "5.0.0" +version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d755237fc0f99d98641540e66abac8bc46a0652f19148ac9e21de2da06b326c9" +checksum = "ffc936cf8a7ea60c58f030fd36a612a48f440610214dc54bc36431f9ea0c3efb" dependencies = [ "libc", "winapi 0.3.9", ] [[package]] -name = "rustc-demangle" -version = "0.1.18" +name = "rsix" +version = "0.23.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e3bad0ee36814ca07d7968269dd4b7ec89ec2da10c4bb613928d3077083c232" +checksum = "1f64c5788d5aab8b75441499d99576a24eb09f76fb267b36fec7e3d970c66431" +dependencies = [ + "bitflags", + "cc", + "errno", + "io-lifetimes", + "itoa", + "libc", + "linux-raw-sys", + "once_cell", + "rustc_version 0.4.0", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" [[package]] name = "rustc-hash" @@ -8519,15 +8670,6 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver 0.9.0", -] - [[package]] name = "rustc_version" version = "0.3.3" @@ -8537,13 +8679,22 @@ dependencies = [ "semver 0.11.0", ] +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver 1.0.4", +] + [[package]] name = "rustls" version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" dependencies = [ - "base64 0.13.0", + "base64", "log", "ring", "sct", @@ -8562,37 +8713,34 @@ dependencies = [ "security-framework", ] +[[package]] +name = "rustversion" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61b3909d758bb75c79f23d4736fac9433868679d3ad2ea7a61e3c25cfda9a088" + [[package]] name = "rw-stream-sink" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4da5fcb054c46f5a5dff833b129285a93d3f0179531735e6c866e8cc307d2020" dependencies = [ - "futures 0.3.17", - "pin-project 0.4.27", + "futures 0.3.19", + "pin-project 0.4.28", "static_assertions", ] [[package]] name = "ryu" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" - -[[package]] -name = "safe-mix" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d3d055a2582e6b00ed7a31c1524040aa391092bf636328350813f3a0605215c" -dependencies = [ - "rustc_version 0.2.3", -] +checksum = "3c9613b5a66ab9ba26415184cfc41156594925a9cf3a2057e57f31ff145f6568" [[package]] name = "salsa20" -version = "0.8.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecbd2eb639fd7cab5804a0837fe373cc2172d15437e804c054a9fb885cb923b0" +checksum = "0c0fbb5f676da676c260ba276a8f43a8dc67cf02d1438423aeb1c677a7212686" dependencies = [ "cipher", ] @@ -8608,8 +8756,8 @@ dependencies = [ [[package]] name = "sc-allocator" -version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +version = "4.1.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "log", "sp-core", @@ -8620,11 +8768,11 @@ dependencies = [ [[package]] name = "sc-authority-discovery" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "async-trait", "derive_more", - "futures 0.3.17", + "futures 0.3.19", "futures-timer 3.0.2", "ip_network", "libp2p", @@ -8647,9 +8795,9 @@ dependencies = [ [[package]] name = "sc-basic-authorship" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ - "futures 0.3.17", + "futures 0.3.19", "futures-timer 3.0.2", "log", "parity-scale-codec", @@ -8670,7 +8818,7 @@ dependencies = [ [[package]] name = "sc-block-builder" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "parity-scale-codec", "sc-client-api", @@ -8686,9 +8834,10 @@ dependencies = [ [[package]] name = "sc-chain-spec" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "impl-trait-for-tuples", + "memmap2 0.5.0", "parity-scale-codec", "sc-chain-spec-derive", "sc-network", @@ -8702,7 +8851,7 @@ dependencies = [ [[package]] name = "sc-chain-spec-derive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "proc-macro-crate 1.1.0", "proc-macro2", @@ -8713,11 +8862,11 @@ dependencies = [ [[package]] name = "sc-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "chrono", "fdlimit", - "futures 0.3.17", + "futures 0.3.19", "hex", "libp2p", "log", @@ -8751,14 +8900,14 @@ dependencies = [ [[package]] name = "sc-client-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "fnv", - "futures 0.3.17", + "futures 0.3.19", "hash-db", "log", "parity-scale-codec", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "sc-executor", "sc-transaction-pool-api", "sc-utils", @@ -8779,7 +8928,7 @@ dependencies = [ [[package]] name = "sc-client-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "hash-db", "kvdb", @@ -8789,7 +8938,7 @@ dependencies = [ "log", "parity-db", "parity-scale-codec", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "sc-client-api", "sc-state-db", "sp-arithmetic", @@ -8804,14 +8953,14 @@ dependencies = [ [[package]] name = "sc-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "async-trait", - "futures 0.3.17", + "futures 0.3.19", "futures-timer 3.0.2", "libp2p", "log", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "sc-client-api", "sc-utils", "serde", @@ -8828,11 +8977,11 @@ dependencies = [ [[package]] name = "sc-consensus-aura" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#66296a0af0aede07c27104e6174a3534b15f14aa" +source = "git+https://github.com/paritytech/substrate?branch=master#b03e8bcf151bbf4c20a7d7faa782366fc3554d58" dependencies = [ "async-trait", "derive_more", - "futures 0.3.17", + "futures 0.3.19", "log", "parity-scale-codec", "sc-block-builder", @@ -8857,19 +9006,19 @@ dependencies = [ [[package]] name = "sc-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "async-trait", "derive_more", "fork-tree", - "futures 0.3.17", + "futures 0.3.19", "log", "merlin", "num-bigint", "num-rational 0.2.4", "num-traits", "parity-scale-codec", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "rand 0.7.3", "retain_mut", "sc-client-api", @@ -8900,10 +9049,10 @@ dependencies = [ [[package]] name = "sc-consensus-babe-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "derive_more", - "futures 0.3.17", + "futures 0.3.19", "jsonrpc-core", "jsonrpc-core-client", "jsonrpc-derive", @@ -8924,7 +9073,7 @@ dependencies = [ [[package]] name = "sc-consensus-epochs" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "fork-tree", "parity-scale-codec", @@ -8937,17 +9086,16 @@ dependencies = [ [[package]] name = "sc-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "async-trait", - "futures 0.3.17", + "futures 0.3.19", "futures-timer 3.0.2", "log", "parity-scale-codec", "sc-client-api", "sc-consensus", "sc-telemetry", - "sp-api", "sp-arithmetic", "sp-blockchain", "sp-consensus", @@ -8963,7 +9111,7 @@ dependencies = [ [[package]] name = "sc-consensus-uncles" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "sc-client-api", "sp-authorship", @@ -8974,18 +9122,20 @@ dependencies = [ [[package]] name = "sc-executor" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "lazy_static", - "libsecp256k1 0.6.0", + "libsecp256k1", "log", + "lru 0.6.6", "parity-scale-codec", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "sc-executor-common", "sc-executor-wasmi", "sc-executor-wasmtime", "sp-api", "sp-core", + "sp-core-hashing-proc-macro", "sp-externalities", "sp-io", "sp-panic-handler", @@ -9000,7 +9150,7 @@ dependencies = [ [[package]] name = "sc-executor-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "derive_more", "environmental", @@ -9018,7 +9168,7 @@ dependencies = [ [[package]] name = "sc-executor-wasmi" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "log", "parity-scale-codec", @@ -9034,7 +9184,7 @@ dependencies = [ [[package]] name = "sc-executor-wasmtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "cfg-if 1.0.0", "libc", @@ -9052,18 +9202,18 @@ dependencies = [ [[package]] name = "sc-finality-grandpa" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "async-trait", "derive_more", "dyn-clone", "finality-grandpa", "fork-tree", - "futures 0.3.17", + "futures 0.3.19", "futures-timer 3.0.2", "log", "parity-scale-codec", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "rand 0.8.4", "sc-block-builder", "sc-client-api", @@ -9089,11 +9239,11 @@ dependencies = [ [[package]] name = "sc-finality-grandpa-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "derive_more", "finality-grandpa", - "futures 0.3.17", + "futures 0.3.19", "jsonrpc-core", "jsonrpc-core-client", "jsonrpc-derive", @@ -9113,10 +9263,10 @@ dependencies = [ [[package]] name = "sc-informant" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ - "ansi_term 0.12.1", - "futures 0.3.17", + "ansi_term", + "futures 0.3.19", "futures-timer 3.0.2", "log", "parity-util-mem", @@ -9130,52 +9280,34 @@ dependencies = [ [[package]] name = "sc-keystore" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "async-trait", "derive_more", "hex", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "serde_json", "sp-application-crypto", "sp-core", "sp-keystore", ] -[[package]] -name = "sc-light" -version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" -dependencies = [ - "hash-db", - "parity-scale-codec", - "parking_lot 0.11.1", - "sc-client-api", - "sc-executor", - "sp-api", - "sp-blockchain", - "sp-core", - "sp-externalities", - "sp-runtime", - "sp-state-machine", -] - [[package]] name = "sc-network" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "async-std", "async-trait", "asynchronous-codec 0.5.0", "bitflags", - "bytes 1.0.1", + "bytes 1.1.0", "cid", "derive_more", "either", "fnv", "fork-tree", - "futures 0.3.17", + "futures 0.3.19", "futures-timer 3.0.2", "hex", "ip_network", @@ -9183,9 +9315,9 @@ dependencies = [ "linked-hash-map", "linked_hash_set", "log", - "lru 0.6.6", + "lru 0.7.1", "parity-scale-codec", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "pin-project 1.0.8", "prost", "prost-build", @@ -9214,13 +9346,13 @@ dependencies = [ [[package]] name = "sc-network-gossip" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ - "futures 0.3.17", + "futures 0.3.19", "futures-timer 3.0.2", "libp2p", "log", - "lru 0.6.6", + "lru 0.7.1", "sc-network", "sp-runtime", "substrate-prometheus-endpoint", @@ -9230,19 +9362,19 @@ dependencies = [ [[package]] name = "sc-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ - "bytes 1.0.1", + "bytes 1.1.0", "fnv", - "futures 0.3.17", + "futures 0.3.19", "futures-timer 3.0.2", "hex", "hyper", "hyper-rustls", - "log", "num_cpus", + "once_cell", "parity-scale-codec", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "rand 0.7.3", "sc-client-api", "sc-network", @@ -9252,14 +9384,15 @@ dependencies = [ "sp-offchain", "sp-runtime", "threadpool", + "tracing", ] [[package]] name = "sc-peerset" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ - "futures 0.3.17", + "futures 0.3.19", "libp2p", "log", "sc-utils", @@ -9269,8 +9402,8 @@ dependencies = [ [[package]] name = "sc-proposer-metrics" -version = "0.9.0" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "log", "substrate-prometheus-endpoint", @@ -9279,15 +9412,15 @@ dependencies = [ [[package]] name = "sc-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ - "futures 0.3.17", + "futures 0.3.19", "hash-db", "jsonrpc-core", "jsonrpc-pubsub", "log", "parity-scale-codec", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "sc-block-builder", "sc-chain-spec", "sc-client-api", @@ -9310,16 +9443,16 @@ dependencies = [ [[package]] name = "sc-rpc-api" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ - "futures 0.3.17", + "futures 0.3.19", "jsonrpc-core", "jsonrpc-core-client", "jsonrpc-derive", "jsonrpc-pubsub", "log", "parity-scale-codec", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "sc-chain-spec", "sc-transaction-pool-api", "serde", @@ -9335,9 +9468,9 @@ dependencies = [ [[package]] name = "sc-rpc-server" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ - "futures 0.3.17", + "futures 0.3.19", "jsonrpc-core", "jsonrpc-http-server", "jsonrpc-ipc-server", @@ -9352,12 +9485,12 @@ dependencies = [ [[package]] name = "sc-service" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "async-trait", "directories", "exit-future", - "futures 0.3.17", + "futures 0.3.19", "futures-timer 3.0.2", "hash-db", "jsonrpc-core", @@ -9365,7 +9498,7 @@ dependencies = [ "log", "parity-scale-codec", "parity-util-mem", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "pin-project 1.0.8", "rand 0.7.3", "sc-block-builder", @@ -9376,7 +9509,6 @@ dependencies = [ "sc-executor", "sc-informant", "sc-keystore", - "sc-light", "sc-network", "sc-offchain", "sc-rpc", @@ -9417,13 +9549,13 @@ dependencies = [ [[package]] name = "sc-state-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "log", "parity-scale-codec", "parity-util-mem", "parity-util-mem-derive", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "sc-client-api", "sp-core", ] @@ -9431,7 +9563,7 @@ dependencies = [ [[package]] name = "sc-sync-state-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "jsonrpc-core", "jsonrpc-core-client", @@ -9453,13 +9585,13 @@ dependencies = [ [[package]] name = "sc-telemetry" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "chrono", - "futures 0.3.17", + "futures 0.3.19", "libp2p", "log", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "pin-project 1.0.8", "rand 0.7.3", "serde", @@ -9471,16 +9603,16 @@ dependencies = [ [[package]] name = "sc-tracing" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ - "ansi_term 0.12.1", + "ansi_term", "atty", "chrono", "lazy_static", "libc", "log", "once_cell", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "regex", "rustc-hash", "sc-client-api", @@ -9502,7 +9634,7 @@ dependencies = [ [[package]] name = "sc-tracing-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "proc-macro-crate 1.1.0", "proc-macro2", @@ -9513,15 +9645,15 @@ dependencies = [ [[package]] name = "sc-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ - "futures 0.3.17", + "futures 0.3.19", "intervalier", "linked-hash-map", "log", "parity-scale-codec", "parity-util-mem", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "retain_mut", "sc-client-api", "sc-transaction-pool-api", @@ -9540,10 +9672,10 @@ dependencies = [ [[package]] name = "sc-transaction-pool-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "derive_more", - "futures 0.3.17", + "futures 0.3.19", "log", "serde", "sp-blockchain", @@ -9554,9 +9686,9 @@ dependencies = [ [[package]] name = "sc-utils" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ - "futures 0.3.17", + "futures 0.3.19", "futures-timer 3.0.2", "lazy_static", "prometheus", @@ -9568,7 +9700,7 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c55b744399c25532d63a0d2789b109df8d46fc93752d46b0782991a931a782f" dependencies = [ - "bitvec 0.20.1", + "bitvec", "cfg-if 1.0.0", "derive_more", "parity-scale-codec", @@ -9606,13 +9738,13 @@ checksum = "021b403afe70d81eea68f6ea12f6b3c9588e5d536a94c3bf80f15e7faa267862" dependencies = [ "arrayref", "arrayvec 0.5.2", - "curve25519-dalek 2.1.0", + "curve25519-dalek 2.1.3", "getrandom 0.1.16", "merlin", "rand 0.7.3", "rand_core 0.5.1", "sha2 0.8.2", - "subtle 2.4.0", + "subtle", "zeroize", ] @@ -9630,9 +9762,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "sct" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3042af939fca8c3453b7af0f1c66e533a15a86169e39de2657310ade8f98d3c" +checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" dependencies = [ "ring", "untrusted", @@ -9649,9 +9781,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.3.1" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23a2ac85147a3a11d77ecf1bc7166ec0b92febfa4461c37944e180f319ece467" +checksum = "525bc1abfda2e1998d152c45cf13e696f76d0a4972310b22fac1658b05df7c87" dependencies = [ "bitflags", "core-foundation", @@ -9662,14 +9794,44 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.3.0" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e4effb91b4b8b6fb7732e670b6cee160278ff8e6bf485c7805d9e319d76e284" +checksum = "a9dd14d83160b528b7bfd66439110573efcfbe281b17fc2ca9f39f550d619c7e" dependencies = [ "core-foundation-sys", "libc", ] +[[package]] +name = "seedling-runtime" +version = "0.1.0" +dependencies = [ + "cumulus-pallet-parachain-system", + "cumulus-primitives-core", + "frame-executive", + "frame-support", + "frame-system", + "log", + "pallet-balances", + "pallet-sudo", + "parachain-info", + "parity-scale-codec", + "scale-info", + "serde", + "sp-api", + "sp-block-builder", + "sp-core", + "sp-inherents", + "sp-io", + "sp-offchain", + "sp-runtime", + "sp-session", + "sp-std", + "sp-transaction-pool", + "sp-version", + "substrate-wasm-builder", +] + [[package]] name = "semver" version = "0.6.0" @@ -9679,15 +9841,6 @@ dependencies = [ "semver-parser 0.7.0", ] -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser 0.7.0", -] - [[package]] name = "semver" version = "0.11.0" @@ -9695,6 +9848,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" dependencies = [ "semver-parser 0.10.2", +] + +[[package]] +name = "semver" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012" +dependencies = [ "serde", ] @@ -9715,18 +9876,28 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.130" +version = "1.0.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" +checksum = "8b9875c23cf305cd1fd7eb77234cbb705f21ea6a72c637a5c6db5fe4b8e7f008" dependencies = [ "serde_derive", ] [[package]] -name = "serde_derive" -version = "1.0.130" +name = "serde_cbor" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" +checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" +dependencies = [ + "half", + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.132" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc0db5cb2556c0e558887d9bbdcf6ac4471e83ff66cf696e5419024d1606276" dependencies = [ "proc-macro2", "quote", @@ -9735,9 +9906,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.68" +version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8" +checksum = "d0ffa0837f2dfa6fb90868c2b5468cad482e175f7dad97e7421951e663f2b527" dependencies = [ "itoa", "ryu", @@ -9758,13 +9929,13 @@ dependencies = [ [[package]] name = "sha-1" -version = "0.9.2" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce3cdf1b5e620a498ee6f2a171885ac7e22f0e12089ec4b3d22b84921792507c" +checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" dependencies = [ "block-buffer 0.9.0", "cfg-if 1.0.0", - "cpuid-bool", + "cpufeatures 0.2.1", "digest 0.9.0", "opaque-debug 0.3.0", ] @@ -9808,12 +9979,11 @@ dependencies = [ [[package]] name = "sharded-slab" -version = "0.1.0" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4921be914e16899a80adefb821f8ddb7974e3f1250223575a44ed994882127" +checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" dependencies = [ "lazy_static", - "loom", ] [[package]] @@ -9828,6 +9998,7 @@ dependencies = [ "frame-executive", "frame-support", "frame-system", + "frame-try-runtime", "log", "parachain-info", "parity-scale-codec", @@ -9852,15 +10023,15 @@ dependencies = [ [[package]] name = "shlex" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42a568c8f2cd051a4d283bd6eb0343ac214c1b0f1ac19f93e1175b2dee38c73d" +checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" [[package]] name = "signal-hook" -version = "0.3.8" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef33d6d0cd06e0840fba9985aab098c147e67e05cee14d412d3345ed14ff30ac" +checksum = "9c98891d737e271a2954825ef19e46bd16bdb98e2746f2eec4f7a4ef7946efd1" dependencies = [ "libc", "signal-hook-registry", @@ -9868,18 +10039,18 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16f1d0fef1604ba8f7a073c7e701f213e056707210e9020af4528e0101ce11a6" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" dependencies = [ "libc", ] [[package]] name = "signature" -version = "1.2.2" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29f060a7d147e33490ec10da418795238fd7545bba241504d6b31a409f2e6210" +checksum = "02658e48d89f2bec991f9a78e69cfa4c316f8d6a6c4ec12fae1aeb263d486788" [[package]] name = "simba" @@ -9895,14 +10066,14 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.2" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" +checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" [[package]] name = "slot-range-helper" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "enumn", "parity-scale-codec", @@ -9913,9 +10084,9 @@ dependencies = [ [[package]] name = "slotmap" -version = "1.0.3" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585cd5dffe4e9e06f6dfdf66708b70aca3f781bed561f4f667b2d9c0d4559e36" +checksum = "e1e08e261d0e8f5c43123b7adf3e4ca1690d655377ac93a03b2c9d3e98de1342" dependencies = [ "version_check", ] @@ -9942,11 +10113,11 @@ dependencies = [ "blake2", "chacha20poly1305", "rand 0.8.4", - "rand_core 0.6.1", + "rand_core 0.6.3", "ring", "rustc_version 0.3.3", "sha2 0.9.8", - "subtle 2.4.0", + "subtle", "x25519-dalek", ] @@ -9963,9 +10134,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e3dfc207c526015c632472a77be09cf1b6e46866581aecae5cc38fb4235dea2" +checksum = "5dc90fe6c7be1a323296982db1836d1ea9e47b6839496dde9a541bc496df3516" dependencies = [ "libc", "winapi 0.3.9", @@ -9973,39 +10144,24 @@ dependencies = [ [[package]] name = "soketto" -version = "0.4.2" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5c71ed3d54db0a699f4948e1bb3e45b450fa31fe602621dee6680361d569c88" +checksum = "41d1c5305e39e09653383c2c7244f2f78b3bcae37cf50c64cb4789c9f5096ec2" dependencies = [ - "base64 0.12.3", - "bytes 0.5.6", + "base64", + "bytes 1.1.0", "flate2", - "futures 0.3.17", - "httparse", - "log", - "rand 0.7.3", - "sha-1 0.9.2", -] - -[[package]] -name = "soketto" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a74e48087dbeed4833785c2f3352b59140095dc192dce966a3bfc155020a439f" -dependencies = [ - "base64 0.13.0", - "bytes 1.0.1", - "futures 0.3.17", + "futures 0.3.19", "httparse", "log", "rand 0.8.4", - "sha-1 0.9.2", + "sha-1 0.9.8", ] [[package]] name = "sp-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "hash-db", "log", @@ -10022,7 +10178,7 @@ dependencies = [ [[package]] name = "sp-api-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "blake2-rfc", "proc-macro-crate 1.1.0", @@ -10033,8 +10189,8 @@ dependencies = [ [[package]] name = "sp-application-crypto" -version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +version = "4.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "parity-scale-codec", "scale-info", @@ -10046,8 +10202,8 @@ dependencies = [ [[package]] name = "sp-arithmetic" -version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +version = "4.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "integer-sqrt", "num-traits", @@ -10062,7 +10218,7 @@ dependencies = [ [[package]] name = "sp-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "parity-scale-codec", "scale-info", @@ -10075,7 +10231,7 @@ dependencies = [ [[package]] name = "sp-authorship" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "async-trait", "parity-scale-codec", @@ -10087,7 +10243,7 @@ dependencies = [ [[package]] name = "sp-block-builder" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "parity-scale-codec", "sp-api", @@ -10099,13 +10255,13 @@ dependencies = [ [[package]] name = "sp-blockchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ - "futures 0.3.17", + "futures 0.3.19", "log", - "lru 0.6.6", + "lru 0.7.1", "parity-scale-codec", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "sp-api", "sp-consensus", "sp-database", @@ -10117,10 +10273,10 @@ dependencies = [ [[package]] name = "sp-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "async-trait", - "futures 0.3.17", + "futures 0.3.19", "futures-timer 3.0.2", "log", "parity-scale-codec", @@ -10136,7 +10292,7 @@ dependencies = [ [[package]] name = "sp-consensus-aura" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#b03e8bcf151bbf4c20a7d7faa782366fc3554d58" dependencies = [ "async-trait", "parity-scale-codec", @@ -10154,7 +10310,7 @@ dependencies = [ [[package]] name = "sp-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "async-trait", "merlin", @@ -10177,10 +10333,11 @@ dependencies = [ [[package]] name = "sp-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "parity-scale-codec", "scale-info", + "serde", "sp-arithmetic", "sp-runtime", ] @@ -10188,7 +10345,7 @@ dependencies = [ [[package]] name = "sp-consensus-vrf" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "parity-scale-codec", "schnorrkel", @@ -10199,27 +10356,28 @@ dependencies = [ [[package]] name = "sp-core" -version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +version = "4.1.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "base58", + "bitflags", "blake2-rfc", "byteorder", "dyn-clonable", "ed25519-dalek", - "futures 0.3.17", + "futures 0.3.19", "hash-db", "hash256-std-hasher", "hex", "impl-serde", "lazy_static", - "libsecp256k1 0.6.0", + "libsecp256k1", "log", "merlin", "num-traits", "parity-scale-codec", "parity-util-mem", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "primitive-types", "rand 0.7.3", "regex", @@ -10228,6 +10386,7 @@ dependencies = [ "secrecy", "serde", "sha2 0.9.8", + "sp-core-hashing", "sp-debug-derive", "sp-externalities", "sp-runtime-interface", @@ -10243,19 +10402,43 @@ dependencies = [ "zeroize", ] +[[package]] +name = "sp-core-hashing" +version = "4.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" +dependencies = [ + "blake2-rfc", + "byteorder", + "sha2 0.9.8", + "sp-std", + "tiny-keccak", + "twox-hash", +] + +[[package]] +name = "sp-core-hashing-proc-macro" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" +dependencies = [ + "proc-macro2", + "quote", + "sp-core-hashing", + "syn", +] + [[package]] name = "sp-database" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "kvdb", - "parking_lot 0.11.1", + "parking_lot 0.11.2", ] [[package]] name = "sp-debug-derive" -version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +version = "4.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "proc-macro2", "quote", @@ -10264,8 +10447,8 @@ dependencies = [ [[package]] name = "sp-externalities" -version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +version = "0.10.0" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "environmental", "parity-scale-codec", @@ -10276,7 +10459,7 @@ dependencies = [ [[package]] name = "sp-finality-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "finality-grandpa", "log", @@ -10294,7 +10477,7 @@ dependencies = [ [[package]] name = "sp-inherents" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "async-trait", "impl-trait-for-tuples", @@ -10307,15 +10490,15 @@ dependencies = [ [[package]] name = "sp-io" -version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +version = "4.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ - "futures 0.3.17", + "futures 0.3.19", "hash-db", - "libsecp256k1 0.6.0", + "libsecp256k1", "log", "parity-scale-codec", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "sp-core", "sp-externalities", "sp-keystore", @@ -10332,25 +10515,25 @@ dependencies = [ [[package]] name = "sp-keyring" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "lazy_static", "sp-core", "sp-runtime", - "strum 0.20.0", + "strum 0.22.0", ] [[package]] name = "sp-keystore" -version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +version = "0.10.0" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "async-trait", "derive_more", - "futures 0.3.17", + "futures 0.3.19", "merlin", "parity-scale-codec", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "schnorrkel", "serde", "sp-core", @@ -10359,8 +10542,8 @@ dependencies = [ [[package]] name = "sp-maybe-compressed-blob" -version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +version = "4.1.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "zstd", ] @@ -10368,7 +10551,7 @@ dependencies = [ [[package]] name = "sp-npos-elections" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "parity-scale-codec", "scale-info", @@ -10383,7 +10566,7 @@ dependencies = [ [[package]] name = "sp-npos-elections-solution-type" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "proc-macro-crate 1.1.0", "proc-macro2", @@ -10394,7 +10577,7 @@ dependencies = [ [[package]] name = "sp-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "sp-api", "sp-core", @@ -10403,16 +10586,18 @@ dependencies = [ [[package]] name = "sp-panic-handler" -version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +version = "4.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "backtrace", + "lazy_static", + "regex", ] [[package]] name = "sp-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "rustc-hash", "serde", @@ -10421,8 +10606,8 @@ dependencies = [ [[package]] name = "sp-runtime" -version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +version = "4.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "either", "hash256-std-hasher", @@ -10443,8 +10628,8 @@ dependencies = [ [[package]] name = "sp-runtime-interface" -version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +version = "4.1.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "impl-trait-for-tuples", "parity-scale-codec", @@ -10460,8 +10645,8 @@ dependencies = [ [[package]] name = "sp-runtime-interface-proc-macro" -version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +version = "4.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "Inflector", "proc-macro-crate 1.1.0", @@ -10472,8 +10657,8 @@ dependencies = [ [[package]] name = "sp-serializer" -version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "serde", "serde_json", @@ -10482,7 +10667,7 @@ dependencies = [ [[package]] name = "sp-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "parity-scale-codec", "scale-info", @@ -10496,7 +10681,7 @@ dependencies = [ [[package]] name = "sp-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "parity-scale-codec", "scale-info", @@ -10506,14 +10691,14 @@ dependencies = [ [[package]] name = "sp-state-machine" -version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +version = "0.10.0" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "hash-db", "log", "num-traits", "parity-scale-codec", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "rand 0.7.3", "smallvec", "sp-core", @@ -10529,13 +10714,13 @@ dependencies = [ [[package]] name = "sp-std" -version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +version = "4.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" [[package]] name = "sp-storage" -version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +version = "4.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "impl-serde", "parity-scale-codec", @@ -10548,7 +10733,7 @@ dependencies = [ [[package]] name = "sp-tasks" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "log", "sp-core", @@ -10561,7 +10746,7 @@ dependencies = [ [[package]] name = "sp-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "async-trait", "futures-timer 3.0.2", @@ -10576,8 +10761,8 @@ dependencies = [ [[package]] name = "sp-tracing" -version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +version = "4.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "parity-scale-codec", "sp-std", @@ -10589,7 +10774,7 @@ dependencies = [ [[package]] name = "sp-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "sp-api", "sp-runtime", @@ -10598,7 +10783,7 @@ dependencies = [ [[package]] name = "sp-transaction-storage-proof" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "async-trait", "log", @@ -10613,8 +10798,8 @@ dependencies = [ [[package]] name = "sp-trie" -version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +version = "4.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "hash-db", "memory-db", @@ -10629,13 +10814,14 @@ dependencies = [ [[package]] name = "sp-version" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "impl-serde", "parity-scale-codec", "parity-wasm 0.42.2", "scale-info", "serde", + "sp-core-hashing-proc-macro", "sp-runtime", "sp-std", "sp-version-proc-macro", @@ -10645,7 +10831,7 @@ dependencies = [ [[package]] name = "sp-version-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "parity-scale-codec", "proc-macro2", @@ -10655,13 +10841,15 @@ dependencies = [ [[package]] name = "sp-wasm-interface" -version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +version = "4.1.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "impl-trait-for-tuples", + "log", "parity-scale-codec", "sp-std", "wasmi", + "wasmtime", ] [[package]] @@ -10672,9 +10860,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] name = "ss58-registry" -version = "1.0.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef2413ecc7946ca99368862851dc1359f1477bc654ecfb135cf3efcb85ceca5f" +checksum = "c83f0afe7e571565ef9aae7b0e4fb30fcaec4ebb9aea2f00489b772782aa03a4" dependencies = [ "Inflector", "proc-macro2", @@ -10710,7 +10898,8 @@ dependencies = [ "frame-system", "frame-system-benchmarking", "frame-system-rpc-runtime-api", - "hex-literal 0.3.3", + "frame-try-runtime", + "hex-literal 0.3.4", "log", "node-primitives", "pallet-asset-tx-payment", @@ -10721,7 +10910,6 @@ dependencies = [ "pallet-collator-selection", "pallet-multisig", "pallet-proxy", - "pallet-randomness-collective-flip", "pallet-session", "pallet-sudo", "pallet-timestamp", @@ -10776,7 +10964,8 @@ dependencies = [ "frame-system", "frame-system-benchmarking", "frame-system-rpc-runtime-api", - "hex-literal 0.3.3", + "frame-try-runtime", + "hex-literal 0.3.4", "log", "node-primitives", "pallet-asset-tx-payment", @@ -10787,7 +10976,6 @@ dependencies = [ "pallet-collator-selection", "pallet-multisig", "pallet-proxy", - "pallet-randomness-collective-flip", "pallet-session", "pallet-sudo", "pallet-timestamp", @@ -10836,7 +11024,7 @@ checksum = "11b73400442027c4adedda20a9f9b7945234a5bd8d5f7e86da22bd5d0622369c" dependencies = [ "cfg_aliases", "libc", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "static_init_macro", ] @@ -10890,27 +11078,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" dependencies = [ "heck", - "proc-macro-error 1.0.4", + "proc-macro-error", "proc-macro2", "quote", "syn", ] -[[package]] -name = "strum" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7318c509b5ba57f18533982607f24070a55d353e90d4cae30c467cdb2ad5ac5c" -dependencies = [ - "strum_macros 0.20.1", -] - -[[package]] -name = "strum" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaf86bbcfd1fa9670b7a129f64fc0c9fcbbfe4f1bc4210e9e98fe71ffc12cde2" - [[package]] name = "strum" version = "0.22.0" @@ -10921,27 +11094,12 @@ dependencies = [ ] [[package]] -name = "strum_macros" -version = "0.20.1" +name = "strum" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee8bc6b87a5112aeeab1f4a9f7ab634fe6cbefc4850006df31267f4cfb9e3149" +checksum = "cae14b91c7d11c9a851d3fbc80a963198998c2a64eec840477fa92d8ce9b70bb" dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "strum_macros" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d06aaeeee809dbc59eb4556183dd927df67db1540de5be8d3ec0b6636358a5ec" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", + "strum_macros 0.23.1", ] [[package]] @@ -10957,22 +11115,35 @@ dependencies = [ ] [[package]] -name = "substrate-bip39" -version = "0.4.2" +name = "strum_macros" +version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bed6646a0159b9935b5d045611560eeef842b78d7adc3ba36f5ca325a13a0236" +checksum = "5bb0dc7ee9c15cea6199cde9a127fa16a4c5819af85395457ad72d68edc85a38" dependencies = [ - "hmac 0.7.1", - "pbkdf2 0.3.0", + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + +[[package]] +name = "substrate-bip39" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49eee6965196b32f882dd2ee85a92b1dbead41b04e53907f269de3b0dc04733c" +dependencies = [ + "hmac 0.11.0", + "pbkdf2 0.8.0", "schnorrkel", - "sha2 0.8.2", + "sha2 0.9.8", "zeroize", ] [[package]] name = "substrate-build-script-utils" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "platforms", ] @@ -10980,10 +11151,10 @@ dependencies = [ [[package]] name = "substrate-frame-rpc-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "frame-system-rpc-runtime-api", - "futures 0.3.17", + "futures 0.3.19", "jsonrpc-core", "jsonrpc-core-client", "jsonrpc-derive", @@ -11001,8 +11172,8 @@ dependencies = [ [[package]] name = "substrate-prometheus-endpoint" -version = "0.9.0" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "async-std", "derive_more", @@ -11016,17 +11187,16 @@ dependencies = [ [[package]] name = "substrate-test-client" version = "2.0.1" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ "async-trait", - "futures 0.3.17", + "futures 0.3.19", "hex", "parity-scale-codec", "sc-client-api", "sc-client-db", "sc-consensus", "sc-executor", - "sc-light", "sc-offchain", "sc-service", "serde", @@ -11043,9 +11213,9 @@ dependencies = [ [[package]] name = "substrate-test-utils" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#b03e8bcf151bbf4c20a7d7faa782366fc3554d58" dependencies = [ - "futures 0.3.17", + "futures 0.3.19", "substrate-test-utils-derive", "tokio", ] @@ -11053,7 +11223,7 @@ dependencies = [ [[package]] name = "substrate-test-utils-derive" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#b03e8bcf151bbf4c20a7d7faa782366fc3554d58" dependencies = [ "proc-macro-crate 1.1.0", "proc-macro2", @@ -11064,9 +11234,9 @@ dependencies = [ [[package]] name = "substrate-wasm-builder" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ - "ansi_term 0.12.1", + "ansi_term", "build-helper", "cargo_metadata", "sp-maybe-compressed-blob", @@ -11078,43 +11248,26 @@ dependencies = [ [[package]] name = "subtle" -version = "1.0.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" - -[[package]] -name = "subtle" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.80" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d010a1623fbd906d51d650a9916aaefc05ffa0e4053ff7fe601167f3e715d194" +checksum = "23a1dfb999630e338648c83e91c59a4e9fb7620f520c3194b6b89e276f2f1959" dependencies = [ "proc-macro2", "quote", "unicode-xid", ] -[[package]] -name = "syn-mid" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baa8e7560a164edb1621a55d18a0c59abf49d360f47aa7b821061dd7eea7fac9" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "synstructure" -version = "0.12.4" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ "proc-macro2", "quote", @@ -11124,15 +11277,15 @@ dependencies = [ [[package]] name = "tap" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36474e732d1affd3a6ed582781b3683df3d0563714c59c39591e8ff707cf078e" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "target-lexicon" -version = "0.12.0" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64ae3b39281e4b14b8123bdbaddd472b7dfe215e444181f2f9d2443c2444f834" +checksum = "d9bffcddbc2458fa3e6058414599e3c838a022abae82e5c67b4f7f80298d5bff" [[package]] name = "tempfile" @@ -11143,7 +11296,7 @@ dependencies = [ "cfg-if 1.0.0", "libc", "rand 0.8.4", - "redox_syscall 0.2.4", + "redox_syscall 0.2.10", "remove_dir_all", "winapi 0.3.9", ] @@ -11157,6 +11310,24 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "termtree" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13a4ec180a2de59b57434704ccfad967f789b12737738798fa08798cd5824c16" + +[[package]] +name = "test-runtime-constants" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" +dependencies = [ + "frame-support", + "polkadot-primitives", + "polkadot-runtime-common", + "smallvec", + "sp-runtime", +] + [[package]] name = "textwrap" version = "0.11.0" @@ -11188,11 +11359,11 @@ dependencies = [ [[package]] name = "thread_local" -version = "1.0.1" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" +checksum = "8018d24e04c95ac8790716a5987d0fec4f8b27249ffa0f7d33f1369bdfb88cbd" dependencies = [ - "lazy_static", + "once_cell", ] [[package]] @@ -11206,9 +11377,9 @@ dependencies = [ [[package]] name = "thrift" -version = "0.13.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c6d965454947cc7266d22716ebfd07b18d84ebaf35eec558586bbb2a8cb6b5b" +checksum = "b82ca8f46f95b3ce96081fe3dd89160fdea970c254bb72925255d1b62aae692e" dependencies = [ "byteorder", "integer-encoding", @@ -11257,10 +11428,20 @@ dependencies = [ ] [[package]] -name = "tinyvec" -version = "1.1.1" +name = "tinytemplate" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317cca572a0e89c3ce0ca1f1bdc9369547fe318a683418e42ac8f59d14701023" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "tinyvec" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" dependencies = [ "tinyvec_macros", ] @@ -11273,18 +11454,17 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.12.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2c2416fdedca8443ae44b4527de1ea633af61d8f7169ffa6e72c5b53d24efcc" +checksum = "fbbf1c778ec206785635ce8ad57fe52b3009ae9e0c9f574a728f3049d3e55838" dependencies = [ - "autocfg", - "bytes 1.0.1", + "bytes 1.1.0", "libc", "memchr", - "mio 0.7.13", + "mio 0.7.14", "num_cpus", "once_cell", - "pin-project-lite 0.2.4", + "pin-project-lite 0.2.7", "signal-hook-registry", "tokio-macros", "winapi 0.3.9", @@ -11292,9 +11472,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "1.4.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "154794c8f499c2619acd19e839294703e9e32e7630ef5f46ea80d4ef0fbee5eb" +checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7" dependencies = [ "proc-macro2", "quote", @@ -11314,27 +11494,27 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b2f3f698253f03119ac0102beaa64f67a67e08074d03a22d18784104543727f" +checksum = "50145484efff8818b5ccd256697f36863f587da82cf8b409c53adf1e840798e3" dependencies = [ "futures-core", - "pin-project-lite 0.2.4", + "pin-project-lite 0.2.7", "tokio", ] [[package]] name = "tokio-util" -version = "0.6.7" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1caa0b0c8d94a049db56b5acf8cba99dc0623aab1b26d5b5f5e2d945846b3592" +checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0" dependencies = [ - "bytes 1.0.1", + "bytes 1.1.0", "futures-core", "futures-io", "futures-sink", "log", - "pin-project-lite 0.2.4", + "pin-project-lite 0.2.7", "tokio", ] @@ -11349,9 +11529,9 @@ dependencies = [ [[package]] name = "tower-service" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e987b6bf443f4b5b3b6f38704195592cca41c5bb7aedd3c3693c7081f8289860" +checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" [[package]] name = "tracing" @@ -11360,7 +11540,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105" dependencies = [ "cfg-if 1.0.0", - "pin-project-lite 0.2.4", + "pin-project-lite 0.2.7", "tracing-attributes", "tracing-core", ] @@ -11422,11 +11602,11 @@ version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" dependencies = [ - "ansi_term 0.12.1", + "ansi_term", "chrono", "lazy_static", "matchers", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "regex", "serde", "serde_json", @@ -11439,17 +11619,11 @@ dependencies = [ "tracing-serde", ] -[[package]] -name = "treeline" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7f741b240f1a48843f9b8e0444fb55fb2a4ff67293b50a9179dfd5ea67f8d41" - [[package]] name = "trie-db" -version = "0.22.6" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9eac131e334e81b6b3be07399482042838adcd7957aa0010231d0813e39e02fa" +checksum = "e3ddae50680c12ef75bfbf58416ca6622fa43d879553f6cb2ed1a817346e1ffe" dependencies = [ "hash-db", "hashbrown", @@ -11460,18 +11634,18 @@ dependencies = [ [[package]] name = "trie-root" -version = "0.16.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "652931506d2c1244d7217a70b99f56718a7b4161b37f04e7cd868072a99f68cd" +checksum = "9a36c5ca3911ed3c9a5416ee6c679042064b93fc637ded67e25f92e68d783891" dependencies = [ "hash-db", ] [[package]] name = "trust-dns-proto" -version = "0.20.1" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d57e219ba600dd96c2f6d82eb79645068e14edbc5c7e27514af40436b88150c" +checksum = "ad0d7f5db438199a6e2609debe3f69f808d074e0a2888ee0bccb45fe234d03f4" dependencies = [ "async-trait", "cfg-if 1.0.0", @@ -11480,7 +11654,7 @@ dependencies = [ "futures-channel", "futures-io", "futures-util", - "idna 0.2.0", + "idna 0.2.3", "ipnet", "lazy_static", "log", @@ -11488,14 +11662,14 @@ dependencies = [ "smallvec", "thiserror", "tinyvec", - "url 2.2.0", + "url 2.2.2", ] [[package]] name = "trust-dns-resolver" -version = "0.20.1" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0437eea3a6da51acc1e946545ff53d5b8fb2611ff1c3bed58522dde100536ae" +checksum = "f6ad17b608a64bd0735e67bde16b0636f8aa8591f831a25d18443ed00a699770" dependencies = [ "cfg-if 1.0.0", "futures-util", @@ -11503,7 +11677,7 @@ dependencies = [ "lazy_static", "log", "lru-cache", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "resolv-conf", "smallvec", "thiserror", @@ -11519,9 +11693,9 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" [[package]] name = "try-runtime-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#969a70d1864fc5d5f6c378bcfd03f1b3ea434049" +source = "git+https://github.com/paritytech/substrate?branch=master#a1fc5cff2ad979697384b24dd52671ccba0bf128" dependencies = [ - "jsonrpsee-ws-client", + "jsonrpsee", "log", "parity-scale-codec", "remote-externalities", @@ -11538,8 +11712,15 @@ dependencies = [ "sp-state-machine", "sp-version", "structopt", + "zstd", ] +[[package]] +name = "tt-call" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e66dcbec4290c69dd03c57e76c2469ea5c7ce109c6dd4351c13055cf71ea055" + [[package]] name = "twox-hash" version = "1.6.1" @@ -11553,9 +11734,9 @@ dependencies = [ [[package]] name = "typenum" -version = "1.12.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" +checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec" [[package]] name = "ucd-trie" @@ -11565,9 +11746,9 @@ checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" [[package]] name = "uint" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e11fe9a9348741cf134085ad57c249508345fe16411b3d7fb4ff2da2f1d6382e" +checksum = "6470ab50f482bde894a037a57064480a246dbfdd5960bd65a44824693f08da5f" dependencies = [ "byteorder", "crunchy", @@ -11586,48 +11767,45 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.4" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" -dependencies = [ - "matches", -] +checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" [[package]] name = "unicode-normalization" -version = "0.1.16" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a13e63ab62dbe32aeee58d1c5408d35c36c392bba5d9d3142287219721afe606" +checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" dependencies = [ "tinyvec", ] [[package]] name = "unicode-segmentation" -version = "1.7.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" +checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" [[package]] name = "unicode-width" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" [[package]] name = "unicode-xid" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" [[package]] name = "universal-hash" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8326b2c654932e3e4f9196e69d08fdf7cfd718e1dc6f66b347e6024a0c961402" +checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" dependencies = [ "generic-array 0.14.4", - "subtle 2.4.0", + "subtle", ] [[package]] @@ -11643,19 +11821,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35581ff83d4101e58b582e607120c7f5ffb17e632a980b1f38334d76b36908b2" dependencies = [ "asynchronous-codec 0.5.0", - "bytes 1.0.1", + "bytes 1.1.0", "futures-io", "futures-util", ] [[package]] name = "unsigned-varint" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f8d425fafb8cd76bc3f22aace4af471d3156301d7508f2107e98fbeae10bc7f" +checksum = "d86a8dc7f45e4c1b0d30e43038c38f274e77af056aa5f74b93c2cf9eb3c1c836" dependencies = [ "asynchronous-codec 0.6.0", - "bytes 1.0.1", + "bytes 1.1.0", "futures-io", "futures-util", ] @@ -11679,36 +11857,31 @@ dependencies = [ [[package]] name = "url" -version = "2.2.0" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5909f2b0817350449ed73e8bcd81c8c3c8d9a7a5d8acba4b27db277f1868976e" +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" dependencies = [ "form_urlencoded", - "idna 0.2.0", + "idna 0.2.3", "matches", "percent-encoding 2.1.0", ] [[package]] name = "value-bag" -version = "1.0.0-alpha.6" +version = "1.0.0-alpha.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b676010e055c99033117c2343b33a40a30b91fecd6c49055ac9cd2d6c305ab1" +checksum = "79923f7731dc61ebfba3633098bf3ac533bbd35ccd8c57e7088d9a5eebe0263f" dependencies = [ "ctor", + "version_check", ] [[package]] name = "vcpkg" -version = "0.2.11" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b00bca6106a5e23f3eee943593759b7fcddb00554332e856d990c893966879fb" - -[[package]] -name = "vec-arena" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eafc1b9b2dfc6f5529177b62cf806484db55b32dc7c9658a118e11bbeb33061d" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "vec_map" @@ -11718,9 +11891,9 @@ checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" [[package]] name = "version_check" -version = "0.9.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" [[package]] name = "void" @@ -11778,9 +11951,9 @@ checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" [[package]] name = "wasm-bindgen" -version = "0.2.73" +version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83240549659d187488f91f33c0f8547cbfef0b2088bc470c116d1d260ef623d9" +checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce" dependencies = [ "cfg-if 1.0.0", "wasm-bindgen-macro", @@ -11788,9 +11961,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.73" +version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae70622411ca953215ca6d06d3ebeb1e915f0f6613e3b495122878d7ebec7dae" +checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b" dependencies = [ "bumpalo", "lazy_static", @@ -11803,9 +11976,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.19" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fe9756085a84584ee9457a002b7cdfe0bfff169f45d2591d8be1345a6780e35" +checksum = "8e8d7523cb1f2a4c96c1317ca690031b714a51cc14e05f712446691f413f5d39" dependencies = [ "cfg-if 1.0.0", "js-sys", @@ -11815,9 +11988,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.73" +version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e734d91443f177bfdb41969de821e15c516931c3c3db3d318fa1b68975d0f6f" +checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -11825,9 +11998,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.73" +version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53739ff08c8a68b0fdbcd54c372b8ab800b1449ab3c9d706503bc7dd1621b2c" +checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab" dependencies = [ "proc-macro2", "quote", @@ -11838,9 +12011,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.73" +version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9a543ae66aa233d14bb765ed9af4a33e81b8b58d1584cf1b47ff8cd0b9e4489" +checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc" [[package]] name = "wasm-gc-api" @@ -11859,9 +12032,9 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f" dependencies = [ - "futures 0.3.17", + "futures 0.3.19", "js-sys", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "pin-utils", "wasm-bindgen", "wasm-bindgen-futures", @@ -11870,9 +12043,9 @@ dependencies = [ [[package]] name = "wasmi" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2ee05bba3d1d994652079893941a2ef9324d2b58a63c31b40678fb7eddd7a5a" +checksum = "ca00c5147c319a8ec91ec1a0edbec31e566ce2c9cc93b3f9bb86a9efd0eb795d" dependencies = [ "downcast-rs", "libc", @@ -11885,24 +12058,24 @@ dependencies = [ [[package]] name = "wasmi-validation" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb8e860796d8be48efef530b60eebf84e74a88bce107374fffb0da97d504b8" +checksum = "165343ecd6c018fc09ebcae280752702c9a2ef3e6f8d02f1cfcbdb53ef6d7937" dependencies = [ "parity-wasm 0.42.2", ] [[package]] name = "wasmparser" -version = "0.80.2" +version = "0.81.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "449167e2832691a1bff24cde28d2804e90e09586a448c8e76984792c44334a6b" +checksum = "98930446519f63d00a836efdc22f67766ceae8dbcc1571379f2bcabc6b2b9abc" [[package]] name = "wasmtime" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "899b1e5261e3d3420860dacfb952871ace9d7ba9f953b314f67aaf9f8e2a4d89" +checksum = "311d06b0c49346d1fbf48a17052e844036b95a7753c1afb34e8c0af3f6b5bb13" dependencies = [ "anyhow", "backtrace", @@ -11932,18 +12105,17 @@ dependencies = [ [[package]] name = "wasmtime-cache" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2493b81d7a9935f7af15e06beec806f256bc974a90a843685f3d61f2fc97058" +checksum = "36147930a4995137dc096e5b17a573b446799be2bbaea433e821ce6a80abe2c5" dependencies = [ "anyhow", - "base64 0.13.0", + "base64", "bincode", "directories-next", - "errno", "file-per-thread-logger", - "libc", "log", + "rsix", "serde", "sha2 0.9.8", "toml", @@ -11953,9 +12125,9 @@ dependencies = [ [[package]] name = "wasmtime-cranelift" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99706bacdf5143f7f967d417f0437cce83a724cf4518cb1a3ff40e519d793021" +checksum = "ab3083a47e1ede38aac06a1d9831640d673f9aeda0b82a64e4ce002f3432e2e7" dependencies = [ "anyhow", "cranelift-codegen", @@ -11963,7 +12135,8 @@ dependencies = [ "cranelift-frontend", "cranelift-native", "cranelift-wasm", - "gimli", + "gimli 0.25.0", + "log", "more-asserts", "object", "target-lexicon", @@ -11974,14 +12147,14 @@ dependencies = [ [[package]] name = "wasmtime-environ" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac42cb562a2f98163857605f02581d719a410c5abe93606128c59a10e84de85b" +checksum = "1c2d194b655321053bc4111a1aa4ead552655c8a17d17264bc97766e70073510" dependencies = [ "anyhow", "cfg-if 1.0.0", "cranelift-entity", - "gimli", + "gimli 0.25.0", "indexmap", "log", "more-asserts", @@ -11995,20 +12168,20 @@ dependencies = [ [[package]] name = "wasmtime-jit" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24f46dd757225f29a419be415ea6fb8558df9b0194f07e3a6a9c99d0e14dd534" +checksum = "864ac8dfe4ce310ac59f16fdbd560c257389cb009ee5d030ac6e30523b023d11" dependencies = [ - "addr2line", + "addr2line 0.16.0", "anyhow", "bincode", "cfg-if 1.0.0", - "gimli", - "libc", + "gimli 0.25.0", "log", "more-asserts", "object", "region", + "rsix", "serde", "target-lexicon", "thiserror", @@ -12020,9 +12193,9 @@ dependencies = [ [[package]] name = "wasmtime-runtime" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0122215a44923f395487048cb0a1d60b5b32c73aab15cf9364b798dbaff0996f" +checksum = "ab97da813a26b98c9abfd3b0c2d99e42f6b78b749c0646344e2e262d212d8c8b" dependencies = [ "anyhow", "backtrace", @@ -12037,6 +12210,7 @@ dependencies = [ "more-asserts", "rand 0.8.4", "region", + "rsix", "thiserror", "wasmtime-environ", "winapi 0.3.9", @@ -12044,9 +12218,9 @@ dependencies = [ [[package]] name = "wasmtime-types" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9b01caf8a204ef634ebac99700e77ba716d3ebbb68a1abbc2ceb6b16dbec9e4" +checksum = "ff94409cc3557bfbbcce6b14520ccd6bd3727e965c0fe68d63ef2c185bf379c6" dependencies = [ "cranelift-entity", "serde", @@ -12056,9 +12230,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.46" +version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222b1ef9334f92a21d3fb53dc3fd80f30836959a90f9274a626d7e06315ba3c3" +checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb" dependencies = [ "js-sys", "wasm-bindgen", @@ -12076,29 +12250,29 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.21.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82015b7e0b8bad8185994674a13a93306bea76cf5a16c5a181382fd3a5ec2376" +checksum = "aabe153544e473b775453675851ecc86863d2a81d786d741f6b76778f2a48940" dependencies = [ "webpki", ] [[package]] -name = "wepoll-sys" -version = "3.0.1" +name = "wepoll-ffi" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fcb14dea929042224824779fbc82d9fab8d2e6d3cbc0ac404de8edf489e77ff" +checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb" dependencies = [ "cc", ] [[package]] name = "westend-runtime" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "beefy-primitives", - "bitvec 0.20.1", + "bitvec", "frame-benchmarking", "frame-election-provider-support", "frame-executive", @@ -12107,7 +12281,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal 0.3.3", + "hex-literal 0.3.4", "log", "pallet-authority-discovery", "pallet-authorship", @@ -12128,6 +12302,7 @@ dependencies = [ "pallet-nicks", "pallet-offences", "pallet-offences-benchmarking", + "pallet-preimage", "pallet-proxy", "pallet-recovery", "pallet-scheduler", @@ -12171,11 +12346,24 @@ dependencies = [ "sp-transaction-pool", "sp-version", "substrate-wasm-builder", + "westend-runtime-constants", "xcm", "xcm-builder", "xcm-executor", ] +[[package]] +name = "westend-runtime-constants" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" +dependencies = [ + "frame-support", + "polkadot-primitives", + "polkadot-runtime-common", + "smallvec", + "sp-runtime", +] + [[package]] name = "westmint-runtime" version = "1.0.0" @@ -12196,7 +12384,8 @@ dependencies = [ "frame-system", "frame-system-benchmarking", "frame-system-rpc-runtime-api", - "hex-literal 0.3.3", + "frame-try-runtime", + "hex-literal 0.3.4", "log", "node-primitives", "pallet-asset-tx-payment", @@ -12207,7 +12396,6 @@ dependencies = [ "pallet-collator-selection", "pallet-multisig", "pallet-proxy", - "pallet-randomness-collective-flip", "pallet-session", "pallet-sudo", "pallet-timestamp", @@ -12244,12 +12432,13 @@ dependencies = [ [[package]] name = "which" -version = "4.0.2" +version = "4.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87c14ef7e1b8b8ecfc75d5eca37949410046e66f15d185c01d70824f1f8111ef" +checksum = "ea187a8ef279bc014ec368c27a920da2024d2a711109bfbe3440585d5cf27ad9" dependencies = [ + "either", + "lazy_static", "libc", - "thiserror", ] [[package]] @@ -12328,19 +12517,19 @@ checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" [[package]] name = "x25519-dalek" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc614d95359fd7afc321b66d2107ede58b246b844cf5d8a0adcca413e439f088" +checksum = "5a0c105152107e3b96f6a00a65e86ce82d9b125230e1c4302940eca58ff71f4f" dependencies = [ - "curve25519-dalek 3.0.0", + "curve25519-dalek 3.2.0", "rand_core 0.5.1", "zeroize", ] [[package]] name = "xcm" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "derivative", "impl-trait-for-tuples", @@ -12352,8 +12541,8 @@ dependencies = [ [[package]] name = "xcm-builder" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "frame-support", "frame-system", @@ -12372,8 +12561,8 @@ dependencies = [ [[package]] name = "xcm-executor" -version = "0.9.12" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +version = "0.9.13" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "frame-benchmarking", "frame-support", @@ -12391,7 +12580,7 @@ dependencies = [ [[package]] name = "xcm-procedural" version = "0.1.0" -source = "git+https://github.com/paritytech/polkadot?branch=master#ee1b80aa117516918bb0591a1ec5a27030e4c64c" +source = "git+https://github.com/paritytech/polkadot?branch=master#d7846bbe6001a06222ffa32d250484c5d35d1962" dependencies = [ "proc-macro2", "quote", @@ -12404,28 +12593,28 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7d9028f208dd5e63c614be69f115c1b53cacc1111437d4c765185856666c107" dependencies = [ - "futures 0.3.17", + "futures 0.3.19", "log", "nohash-hasher", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "rand 0.8.4", "static_assertions", ] [[package]] name = "zeroize" -version = "1.4.2" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf68b08513768deaa790264a7fac27a58cbf2705cfcdc9448362229217d7e970" +checksum = "d68d9dcec5f9b43a30d38c49f91dfedfaac384cb8f085faca366c26207dd1619" dependencies = [ "zeroize_derive", ] [[package]] name = "zeroize_derive" -version = "1.0.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3f369ddb18862aba61aa49bf31e74d29f0f162dec753063200e1dc084345d16" +checksum = "65f1a51723ec88c66d5d1fe80c841f17f63587d6691901d66be9bec6c3b51f73" dependencies = [ "proc-macro2", "quote", @@ -12435,18 +12624,18 @@ dependencies = [ [[package]] name = "zstd" -version = "0.9.0+zstd.1.5.0" +version = "0.9.1+zstd.1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07749a5dc2cb6b36661290245e350f15ec3bbb304e493db54a1d354480522ccd" +checksum = "538b8347df9257b7fbce37677ef7535c00a3c7bf1f81023cc328ed7fe4b41de8" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "4.1.1+zstd.1.5.0" +version = "4.1.2+zstd.1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c91c90f2c593b003603e5e0493c837088df4469da25aafff8bce42ba48caf079" +checksum = "9fb4cfe2f6e6d35c5d27ecd9d256c4b6f7933c4895654917460ec56c29336cc1" dependencies = [ "libc", "zstd-sys", @@ -12454,9 +12643,9 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "1.6.1+zstd.1.5.0" +version = "1.6.2+zstd.1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "615120c7a2431d16cf1cf979e7fc31ba7a5b5e5707b29c8a99e5dbf8a8392a33" +checksum = "2daf2f248d9ea44454bfcb2516534e8b8ad2fc91bf818a1885495fc42bc8ac9f" dependencies = [ "cc", "libc", diff --git a/Cargo.toml b/Cargo.toml index c89e88b214..d3725ff4a5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ members = [ "client/network", "client/pov-recovery", "client/service", - "pallets/asset-tx-payment", + "client/relay-chain-interface", "pallets/aura-ext", "pallets/collator-selection", "pallets/dmp-queue", @@ -25,7 +25,7 @@ members = [ "polkadot-parachains/", "polkadot-parachains/pallets/parachain-info", "polkadot-parachains/pallets/ping", - "polkadot-parachains/rococo", + "polkadot-parachains/rococo-parachain", "polkadot-parachains/shell", "polkadot-parachains/parachains-common", "polkadot-parachains/statemint", @@ -35,7 +35,6 @@ members = [ "test/relay-sproof-builder", "test/relay-validation-worker-provider", "test/runtime", - "test/runtime-upgrade", "test/service", ] diff --git a/README.md b/README.md index a04bf18ca0..ab096e2059 100644 --- a/README.md +++ b/README.md @@ -41,13 +41,13 @@ Statemint is a common good parachain providing an asset store for the Polkadot e To run a Statemine or Westmint node (Statemint is not deployed, yet) you will need to compile the `polkadot-collator` binary: -```sh +```bash cargo build --release --locked -p polkadot-collator ``` Once the executable is built, launch the parachain node via: -```sh +```bash CHAIN=westmint # or statemine ./target/release/polkadot-collator --chain $CHAIN ``` @@ -56,15 +56,10 @@ Refer to the [setup instructions below](#local-setup) to run a local network for # Rococo :crown: -[Rococo](https://polkadot.js.org/apps/?rpc=wss://rococo-rpc.polkadot.io) is the testnet for -parachains. It currently runs the parachains -[Tick](https://polkadot.js.org/apps/?rpc=wss://tick-rpc.polkadot.io), -[Trick](https://polkadot.js.org/apps/?rpc=wss://trick-rpc.polkadot.io) and -[Track](https://polkadot.js.org/apps/?rpc=wss://track-rpc.polkadot.io). +[Rococo](https://polkadot.js.org/apps/?rpc=wss://rococo-rpc.polkadot.io) is becoming a [Community Parachain Testbed](https://polkadot.network/blog/rococo-revamp-becoming-a-community-parachain-testbed/) for parachain teams in the Polkadot ecosystem. It supports multiple parachains with the differentiation of long-term connections and recurring short-term connections, to see which parachains are currently connected and how long they will be connected for [see here](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Frococo-rpc.polkadot.io#/parachains). Rococo is an elaborate style of design and the name describes the painstaking effort that has gone -into this project. Tick, Trick and Track are the German names for the cartoon ducks known to English -speakers as Huey, Dewey and Louie. +into this project. ## Build & Launch Rococo Collators @@ -73,7 +68,7 @@ eventually be included by the relay chain for a parachain. To run a Rococo collator you will need to compile the following binary: -``` +```bash cargo build --release --locked -p polkadot-collator ``` @@ -93,18 +88,13 @@ If you want to reproduce other steps of CI process you can use the following Once the executable is built, launch collators for each parachain (repeat once each for chain `tick`, `trick`, `track`): -``` +```bash ./target/release/polkadot-collator --chain $CHAIN --validator ``` ## Parachains -The parachains of Rococo all use the same runtime code. The only difference between them is the -parachain ID used for registration with the relay chain: - -- Tick: 100 -- Trick: 110 -- Track: 120 +- [Canvas - WASM Smart Contract](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Frococo-canvas-rpc.polkadot.io#/explorer) The network uses horizontal message passing (HRMP) to enable communication between parachains and the relay chain and, in turn, between parachains. This means that every message is sent to the relay @@ -154,19 +144,27 @@ cargo build --release # Parachain Full Node 1 ./target/release/polkadot-collator --tmp --parachain-id --port 40337 --ws-port 9948 -- --execution wasm --chain ../polkadot/rococo-local-cfde.json --port 30337 ``` + ### Register the parachain + ![image](https://user-images.githubusercontent.com/2915325/99548884-1be13580-2987-11eb-9a8b-20be658d34f9.png) -## Build the docker image +## Containerize -After building `polkadot-collator` with cargo or with Parity docker image as documented in [this chapter](#build--launch-rococo-collators), the following will allow producting a new docker image where the compiled binary is injected: +After building `polkadot-collator` with cargo or with Parity CI image as documented in [this chapter](#build--launch-rococo-collators), +the following will allow producing a new docker image where the compiled binary is injected: -``` +```bash ./docker/scripts/build-injected-image.sh ``` -You may then start a new contaier: +Alternatively, you can build an image with a builder pattern: -``` +```bash +docker build --tag $OWNER/$IMAGE_NAME --file ./docker/polkadot-collator_builder.Containerfile . + +You may then run your new container: + +```bash docker run --rm -it $OWNER/$IMAGE_NAME --collator --tmp --parachain-id 1000 --execution wasm --chain /specs/westmint.json ``` diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index 90b866f64e..513a7db392 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -2,7 +2,7 @@ name = "cumulus-client-cli" version = "0.1.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" [dependencies] structopt = "0.3.3" diff --git a/client/cli/src/lib.rs b/client/cli/src/lib.rs index 6f4f97c627..0f031d442f 100644 --- a/client/cli/src/lib.rs +++ b/client/cli/src/lib.rs @@ -30,7 +30,7 @@ use std::{ }; use structopt::StructOpt; -/// The `purge-chain` command used to remove the whole chain: the parachain and the relaychain. +/// The `purge-chain` command used to remove the whole chain: the parachain and the relay chain. #[derive(Debug, StructOpt)] pub struct PurgeChainCmd { /// The base struct of the purge-chain command. @@ -125,10 +125,6 @@ pub struct RunCmd { #[structopt(flatten)] pub base: sc_cli::RunCmd, - /// Id of the parachain this collator collates for. - #[structopt(long)] - pub parachain_id: Option, - /// Run node as collator. /// /// Note that this is the same as running with `--validator`. @@ -137,13 +133,11 @@ pub struct RunCmd { } /// A non-redundant version of the `RunCmd` that sets the `validator` field when the -/// original `RunCmd` had the `colaltor` field. +/// original `RunCmd` had the `collator` field. /// This is how we make `--collator` imply `--validator`. pub struct NormalizedRunCmd { /// The cumulus RunCmd inherents from sc_cli's pub base: sc_cli::RunCmd, - /// Id of the parachain this collator collates for. - pub parachain_id: Option, } impl RunCmd { @@ -153,7 +147,7 @@ impl RunCmd { new_base.validator = self.base.validator || self.collator; - NormalizedRunCmd { base: new_base, parachain_id: self.parachain_id } + NormalizedRunCmd { base: new_base } } } @@ -204,8 +198,9 @@ impl sc_cli::CliConfiguration for NormalizedRunCmd { fn prometheus_config( &self, default_listen_port: u16, + chain_spec: &Box, ) -> sc_cli::Result> { - self.base.prometheus_config(default_listen_port) + self.base.prometheus_config(default_listen_port, chain_spec) } fn disable_grandpa(&self) -> sc_cli::Result { diff --git a/client/collator/Cargo.toml b/client/collator/Cargo.toml index 6f65d48029..e54a04e200 100644 --- a/client/collator/Cargo.toml +++ b/client/collator/Cargo.toml @@ -2,7 +2,7 @@ name = "cumulus-client-collator" version = "0.1.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" [dependencies] # Substrate dependencies @@ -22,6 +22,7 @@ polkadot-node-subsystem = { git = "https://github.com/paritytech/polkadot", bran cumulus-client-network = { path = "../network" } cumulus-client-consensus-common = { path = "../consensus/common" } cumulus-primitives-core = { path = "../../primitives/core" } +cumulus-relay-chain-interface = { path = "../relay-chain-interface" } # Other dependencies codec = { package = "parity-scale-codec", version = "2.3.0", features = [ "derive" ] } diff --git a/client/collator/src/lib.rs b/client/collator/src/lib.rs index 4799d441ee..b380c4ce62 100644 --- a/client/collator/src/lib.rs +++ b/client/collator/src/lib.rs @@ -17,7 +17,9 @@ //! Cumulus Collator implementation for Substrate. use cumulus_client_network::WaitToAnnounce; -use cumulus_primitives_core::{CollectCollationInfo, ParachainBlockData, PersistedValidationData}; +use cumulus_primitives_core::{ + relay_chain::Hash as PHash, CollectCollationInfo, ParachainBlockData, PersistedValidationData, +}; use sc_client_api::BlockBackend; use sp_api::ProvideRuntimeApi; @@ -34,7 +36,7 @@ use polkadot_node_primitives::{ }; use polkadot_node_subsystem::messages::{CollationGenerationMessage, CollatorProtocolMessage}; use polkadot_overseer::Handle as OverseerHandle; -use polkadot_primitives::v1::{CollatorPair, Hash as PHash, HeadData, Id as ParaId}; +use polkadot_primitives::v1::{CollatorPair, HeadData, Id as ParaId}; use codec::{Decode, Encode}; use futures::{channel::oneshot, FutureExt}; @@ -390,7 +392,7 @@ mod tests { .build() .expect("Builds overseer"); - spawner.spawn("overseer", overseer.run().then(|_| async { () }).boxed()); + spawner.spawn("overseer", None, overseer.run().then(|_| async { () }).boxed()); let collator_start = start_collator(StartCollatorParams { runtime_api: client.clone(), @@ -428,8 +430,8 @@ mod tests { assert_eq!(1, *block.header().number()); // Ensure that we did not include `:code` in the proof. - let db = block - .storage_proof() + let proof = block.storage_proof(); + let db = proof .to_storage_proof::(Some(header.state_root())) .unwrap() .0 diff --git a/client/consensus/aura/Cargo.toml b/client/consensus/aura/Cargo.toml index 35a0e47fd8..445b42635e 100644 --- a/client/consensus/aura/Cargo.toml +++ b/client/consensus/aura/Cargo.toml @@ -3,7 +3,7 @@ name = "cumulus-client-consensus-aura" description = "AURA consensus algorithm for parachains" version = "0.1.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" [dependencies] # Substrate dependencies @@ -24,9 +24,6 @@ sc-telemetry = { git = "https://github.com/paritytech/substrate", branch = "mast sc-consensus = { git = "https://github.com/paritytech/substrate", branch = "master" } substrate-prometheus-endpoint = { git = "https://github.com/paritytech/substrate", branch = "master" } -# Polkadot dependencies -polkadot-client = { git = "https://github.com/paritytech/polkadot", branch = "master" } - # Cumulus dependencies cumulus-client-consensus-common = { path = "../common" } cumulus-primitives-core = { path = "../../../primitives/core" } diff --git a/client/consensus/aura/src/import_queue.rs b/client/consensus/aura/src/import_queue.rs index eaf7eac446..31ed577985 100644 --- a/client/consensus/aura/src/import_queue.rs +++ b/client/consensus/aura/src/import_queue.rs @@ -24,12 +24,12 @@ use sc_consensus_slots::InherentDataProviderExt; use sc_telemetry::TelemetryHandle; use sp_api::{ApiExt, ProvideRuntimeApi}; use sp_block_builder::BlockBuilder as BlockBuilderApi; -use sp_blockchain::{HeaderBackend, ProvideCache}; +use sp_blockchain::HeaderBackend; use sp_consensus::{CanAuthorWith, Error as ConsensusError}; -use sp_consensus_aura::{digests::CompatibleDigestItem, AuraApi}; +use sp_consensus_aura::AuraApi; use sp_core::crypto::Pair; use sp_inherents::CreateInherentDataProviders; -use sp_runtime::traits::{Block as BlockT, DigestItemFor}; +use sp_runtime::traits::Block as BlockT; use std::{fmt::Debug, hash::Hash, sync::Arc}; use substrate_prometheus_endpoint::Registry; @@ -69,7 +69,6 @@ where C: 'static + ProvideRuntimeApi + BlockOf - + ProvideCache + Send + Sync + AuxStore @@ -79,7 +78,6 @@ where + Send + Sync + 'static, - DigestItemFor: CompatibleDigestItem, P: Pair + Send + Sync + 'static, P::Public: Clone + Eq + Send + Sync + Hash + Debug + Codec, P::Signature: Codec, diff --git a/client/consensus/aura/src/lib.rs b/client/consensus/aura/src/lib.rs index 9af7aad183..e65aa6ce97 100644 --- a/client/consensus/aura/src/lib.rs +++ b/client/consensus/aura/src/lib.rs @@ -26,19 +26,16 @@ use codec::{Decode, Encode}; use cumulus_client_consensus_common::{ ParachainBlockImport, ParachainCandidate, ParachainConsensus, }; -use cumulus_primitives_core::{ - relay_chain::v1::{Block as PBlock, Hash as PHash, ParachainHost}, - PersistedValidationData, -}; +use cumulus_primitives_core::{relay_chain::v1::Hash as PHash, PersistedValidationData}; + use futures::lock::Mutex; -use polkadot_client::ClientHandle; -use sc_client_api::{backend::AuxStore, Backend, BlockOf}; +use sc_client_api::{backend::AuxStore, BlockOf}; use sc_consensus::BlockImport; use sc_consensus_slots::{BackoffAuthoringBlocksStrategy, SlotInfo}; use sc_telemetry::TelemetryHandle; use sp_api::ProvideRuntimeApi; use sp_application_crypto::AppPublic; -use sp_blockchain::{HeaderBackend, ProvideCache}; +use sp_blockchain::HeaderBackend; use sp_consensus::{ EnableProofRecording, Environment, ProofRecording, Proposer, SlotData, SyncOracle, }; @@ -46,8 +43,8 @@ use sp_consensus_aura::AuraApi; use sp_core::crypto::Pair; use sp_inherents::{CreateInherentDataProviders, InherentData, InherentDataProvider}; use sp_keystore::SyncCryptoStorePtr; -use sp_runtime::traits::{Block as BlockT, HashFor, Header as HeaderT, Member, NumberFor}; -use std::{convert::TryFrom, hash::Hash, marker::PhantomData, sync::Arc}; +use sp_runtime::traits::{Block as BlockT, Header as HeaderT, Member, NumberFor}; +use std::{convert::TryFrom, hash::Hash, sync::Arc}; mod import_queue; @@ -60,10 +57,8 @@ pub use sc_consensus_slots::InherentDataProviderExt; const LOG_TARGET: &str = "aura::cumulus"; /// The implementation of the AURA consensus for parachains. -pub struct AuraConsensus { +pub struct AuraConsensus { create_inherent_data_providers: Arc, - relay_chain_client: Arc, - relay_chain_backend: Arc, aura_worker: Arc< Mutex< dyn sc_consensus_slots::SlotWorker::Proof> @@ -74,53 +69,42 @@ pub struct AuraConsensus { slot_duration: SlotDuration, } -impl Clone for AuraConsensus { +impl Clone for AuraConsensus { fn clone(&self) -> Self { Self { create_inherent_data_providers: self.create_inherent_data_providers.clone(), - relay_chain_backend: self.relay_chain_backend.clone(), - relay_chain_client: self.relay_chain_client.clone(), aura_worker: self.aura_worker.clone(), slot_duration: self.slot_duration, } } } -impl AuraConsensus +impl AuraConsensus where B: BlockT, - RClient: ProvideRuntimeApi, - RClient::Api: ParachainHost, - RBackend: Backend, - CIDP: CreateInherentDataProviders, + CIDP: CreateInherentDataProviders + 'static, CIDP::InherentDataProviders: InherentDataProviderExt, { - /// Create a new instance of AURA consensus. - pub fn new( - para_client: Arc, - block_import: BI, - sync_oracle: SO, - proposer_factory: PF, - force_authoring: bool, - backoff_authoring_blocks: Option, - keystore: SyncCryptoStorePtr, - create_inherent_data_providers: CIDP, - polkadot_client: Arc, - polkadot_backend: Arc, - slot_duration: SlotDuration, - telemetry: Option, - block_proposal_slot_portion: SlotProportion, - max_block_proposal_slot_portion: Option, - ) -> Self + /// Create a new boxed instance of AURA consensus. + pub fn build( + BuildAuraConsensusParams { + proposer_factory, + create_inherent_data_providers, + block_import, + para_client, + backoff_authoring_blocks, + sync_oracle, + keystore, + force_authoring, + slot_duration, + telemetry, + block_proposal_slot_portion, + max_block_proposal_slot_portion, + }: BuildAuraConsensusParams, + ) -> Box> where - Client: ProvideRuntimeApi - + BlockOf - + ProvideCache - + AuxStore - + HeaderBackend - + Send - + Sync - + 'static, + Client: + ProvideRuntimeApi + BlockOf + AuxStore + HeaderBackend + Send + Sync + 'static, Client::Api: AuraApi, BI: BlockImport> + Send + Sync + 'static, SO: SyncOracle + Send + Sync + Clone + 'static, @@ -154,13 +138,11 @@ where }, ); - Self { + Box::new(Self { create_inherent_data_providers: Arc::new(create_inherent_data_providers), - relay_chain_backend: polkadot_backend, - relay_chain_client: polkadot_client, aura_worker: Arc::new(Mutex::new(worker)), slot_duration, - } + }) } /// Create the inherent data. @@ -200,13 +182,10 @@ where } #[async_trait::async_trait] -impl ParachainConsensus for AuraConsensus +impl ParachainConsensus for AuraConsensus where B: BlockT, - RClient: ProvideRuntimeApi + Send + Sync, - RClient::Api: ParachainHost, - RBackend: Backend, - CIDP: CreateInherentDataProviders + Send + Sync, + CIDP: CreateInherentDataProviders + Send + Sync + 'static, CIDP::InherentDataProviders: InherentDataProviderExt + Send, { async fn produce_candidate( @@ -238,12 +217,10 @@ where } /// Paramaters of [`build_aura_consensus`]. -pub struct BuildAuraConsensusParams { +pub struct BuildAuraConsensusParams { pub proposer_factory: PF, pub create_inherent_data_providers: CIDP, pub block_import: BI, - pub relay_chain_client: polkadot_client::Client, - pub relay_chain_backend: Arc, pub para_client: Arc, pub backoff_authoring_blocks: Option, pub sync_oracle: SO, @@ -254,250 +231,3 @@ pub struct BuildAuraConsensusParams { pub block_proposal_slot_portion: SlotProportion, pub max_block_proposal_slot_portion: Option, } - -/// Build the [`AuraConsensus`]. -/// -/// Returns a boxed [`ParachainConsensus`]. -pub fn build_aura_consensus( - BuildAuraConsensusParams { - proposer_factory, - create_inherent_data_providers, - block_import, - relay_chain_client, - relay_chain_backend, - para_client, - backoff_authoring_blocks, - sync_oracle, - keystore, - force_authoring, - slot_duration, - telemetry, - block_proposal_slot_portion, - max_block_proposal_slot_portion, - }: BuildAuraConsensusParams, -) -> Box> -where - Block: BlockT, - RBackend: Backend + 'static, - CIDP: CreateInherentDataProviders - + Send - + Sync - + 'static, - CIDP::InherentDataProviders: InherentDataProviderExt + Send, - Client: ProvideRuntimeApi - + BlockOf - + ProvideCache - + AuxStore - + HeaderBackend - + Send - + Sync - + 'static, - Client::Api: AuraApi, - BI: BlockImport> - + Send - + Sync - + 'static, - SO: SyncOracle + Send + Sync + Clone + 'static, - BS: BackoffAuthoringBlocksStrategy> + Send + Sync + 'static, - PF: Environment + Send + Sync + 'static, - PF::Proposer: Proposer< - Block, - Error = Error, - Transaction = sp_api::TransactionFor, - ProofRecording = EnableProofRecording, - Proof = ::Proof, - >, - Error: std::error::Error + Send + From + 'static, - P: Pair + Send + Sync, - P::Public: AppPublic + Hash + Member + Encode + Decode, - P::Signature: TryFrom> + Hash + Member + Encode + Decode, -{ - AuraConsensusBuilder::::new( - proposer_factory, - block_import, - create_inherent_data_providers, - relay_chain_client, - relay_chain_backend, - para_client, - backoff_authoring_blocks, - sync_oracle, - force_authoring, - keystore, - slot_duration, - telemetry, - block_proposal_slot_portion, - max_block_proposal_slot_portion, - ) - .build() -} - -/// Aura consensus builder. -/// -/// Builds a [`AuraConsensus`] for a parachain. As this requires -/// a concrete relay chain client instance, the builder takes a [`polkadot_client::Client`] -/// that wraps this concrete instance. By using [`polkadot_client::ExecuteWithClient`] -/// the builder gets access to this concrete instance. -struct AuraConsensusBuilder { - _phantom: PhantomData<(Block, Error, P)>, - proposer_factory: PF, - create_inherent_data_providers: CIDP, - block_import: BI, - relay_chain_backend: Arc, - relay_chain_client: polkadot_client::Client, - para_client: Arc, - backoff_authoring_blocks: Option, - sync_oracle: SO, - force_authoring: bool, - keystore: SyncCryptoStorePtr, - slot_duration: SlotDuration, - telemetry: Option, - block_proposal_slot_portion: SlotProportion, - max_block_proposal_slot_portion: Option, -} - -impl - AuraConsensusBuilder -where - Block: BlockT, - RBackend: Backend + 'static, - CIDP: CreateInherentDataProviders - + Send - + Sync - + 'static, - CIDP::InherentDataProviders: InherentDataProviderExt + Send, - Client: ProvideRuntimeApi - + BlockOf - + ProvideCache - + AuxStore - + HeaderBackend - + Send - + Sync - + 'static, - Client::Api: AuraApi, - BI: BlockImport> - + Send - + Sync - + 'static, - SO: SyncOracle + Send + Sync + Clone + 'static, - BS: BackoffAuthoringBlocksStrategy> + Send + Sync + 'static, - PF: Environment + Send + Sync + 'static, - PF::Proposer: Proposer< - Block, - Error = Error, - Transaction = sp_api::TransactionFor, - ProofRecording = EnableProofRecording, - Proof = ::Proof, - >, - Error: std::error::Error + Send + From + 'static, - P: Pair + Send + Sync, - P::Public: AppPublic + Hash + Member + Encode + Decode, - P::Signature: TryFrom> + Hash + Member + Encode + Decode, -{ - /// Create a new instance of the builder. - fn new( - proposer_factory: PF, - block_import: BI, - create_inherent_data_providers: CIDP, - relay_chain_client: polkadot_client::Client, - relay_chain_backend: Arc, - para_client: Arc, - backoff_authoring_blocks: Option, - sync_oracle: SO, - force_authoring: bool, - keystore: SyncCryptoStorePtr, - slot_duration: SlotDuration, - telemetry: Option, - block_proposal_slot_portion: SlotProportion, - max_block_proposal_slot_portion: Option, - ) -> Self { - Self { - _phantom: PhantomData, - proposer_factory, - block_import, - create_inherent_data_providers, - relay_chain_backend, - relay_chain_client, - para_client, - backoff_authoring_blocks, - sync_oracle, - force_authoring, - keystore, - slot_duration, - telemetry, - block_proposal_slot_portion, - max_block_proposal_slot_portion, - } - } - - /// Build the relay chain consensus. - fn build(self) -> Box> { - self.relay_chain_client.clone().execute_with(self) - } -} - -impl polkadot_client::ExecuteWithClient - for AuraConsensusBuilder -where - Block: BlockT, - RBackend: Backend + 'static, - CIDP: CreateInherentDataProviders - + Send - + Sync - + 'static, - CIDP::InherentDataProviders: InherentDataProviderExt + Send, - Client: ProvideRuntimeApi - + BlockOf - + ProvideCache - + AuxStore - + HeaderBackend - + Send - + Sync - + 'static, - Client::Api: AuraApi, - BI: BlockImport> - + Send - + Sync - + 'static, - SO: SyncOracle + Send + Sync + Clone + 'static, - BS: BackoffAuthoringBlocksStrategy> + Send + Sync + 'static, - PF: Environment + Send + Sync + 'static, - PF::Proposer: Proposer< - Block, - Error = Error, - Transaction = sp_api::TransactionFor, - ProofRecording = EnableProofRecording, - Proof = ::Proof, - >, - Error: std::error::Error + Send + From + 'static, - P: Pair + Send + Sync, - P::Public: AppPublic + Hash + Member + Encode + Decode, - P::Signature: TryFrom> + Hash + Member + Encode + Decode, -{ - type Output = Box>; - - fn execute_with_client(self, client: Arc) -> Self::Output - where - >::StateBackend: sp_api::StateBackend>, - PBackend: Backend, - PBackend::State: sp_api::StateBackend, - Api: polkadot_client::RuntimeApiCollection, - PClient: polkadot_client::AbstractClient + 'static, - { - Box::new(AuraConsensus::new::( - self.para_client, - self.block_import, - self.sync_oracle, - self.proposer_factory, - self.force_authoring, - self.backoff_authoring_blocks, - self.keystore, - self.create_inherent_data_providers, - client.clone(), - self.relay_chain_backend, - self.slot_duration, - self.telemetry, - self.block_proposal_slot_portion, - self.max_block_proposal_slot_portion, - )) - } -} diff --git a/client/consensus/common/Cargo.toml b/client/consensus/common/Cargo.toml index e8a66b3f25..057f0b3496 100644 --- a/client/consensus/common/Cargo.toml +++ b/client/consensus/common/Cargo.toml @@ -3,7 +3,7 @@ name = "cumulus-client-consensus-common" description = "Cumulus specific common consensus implementations" version = "0.1.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" [dependencies] # Substrate deps @@ -18,6 +18,9 @@ sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master" } # Polkadot deps polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "master" } +# Cumulus deps +cumulus-relay-chain-interface = { path = "../../relay-chain-interface" } + # Other deps futures = { version = "0.3.8", features = ["compat"] } codec = { package = "parity-scale-codec", version = "2.3.0", features = [ "derive" ] } diff --git a/client/consensus/common/src/parachain_consensus.rs b/client/consensus/common/src/parachain_consensus.rs index 47a5b4dbaa..224e3e5fd9 100644 --- a/client/consensus/common/src/parachain_consensus.rs +++ b/client/consensus/common/src/parachain_consensus.rs @@ -14,11 +14,11 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . +use cumulus_relay_chain_interface::RelayChainInterface; use sc_client_api::{ Backend, BlockBackend, BlockImportNotification, BlockchainEvents, Finalizer, UsageProvider, }; use sc_consensus::{BlockImport, BlockImportParams, ForkChoiceStrategy}; -use sp_api::ProvideRuntimeApi; use sp_blockchain::{Error as ClientError, Result as ClientResult}; use sp_consensus::{BlockOrigin, BlockStatus}; use sp_runtime::{ @@ -26,9 +26,7 @@ use sp_runtime::{ traits::{Block as BlockT, Header as HeaderT}, }; -use polkadot_primitives::v1::{ - Block as PBlock, Id as ParaId, OccupiedCoreAssumption, ParachainHost, -}; +use polkadot_primitives::v1::{Block as PBlock, Id as ParaId, OccupiedCoreAssumption}; use codec::Decode; use futures::{future, select, FutureExt, Stream, StreamExt}; @@ -370,10 +368,9 @@ where } } -impl RelaychainClient for Arc +impl RelaychainClient for RCInterface where - T: sc_client_api::BlockchainEvents + ProvideRuntimeApi + 'static + Send + Sync, - >::Api: ParachainHost, + RCInterface: RelayChainInterface + Clone + 'static, { type Error = ClientError; @@ -410,8 +407,7 @@ where at: &BlockId, para_id: ParaId, ) -> ClientResult>> { - self.runtime_api() - .persisted_validation_data(at, para_id, OccupiedCoreAssumption::TimedOut) + self.persisted_validation_data(at, para_id, OccupiedCoreAssumption::TimedOut) .map(|s| s.map(|s| s.parent_head.0)) .map_err(Into::into) } diff --git a/client/consensus/relay-chain/Cargo.toml b/client/consensus/relay-chain/Cargo.toml index 5da2af5bf1..e4006ed731 100644 --- a/client/consensus/relay-chain/Cargo.toml +++ b/client/consensus/relay-chain/Cargo.toml @@ -3,7 +3,7 @@ name = "cumulus-client-consensus-relay-chain" description = "The relay-chain provided consensus algorithm" version = "0.1.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" [dependencies] # Substrate deps @@ -19,11 +19,11 @@ sc-consensus = { git = "https://github.com/paritytech/substrate", branch = "mast substrate-prometheus-endpoint = { git = "https://github.com/paritytech/substrate", branch = "master" } # Polkadot dependencies -polkadot-client = { git = "https://github.com/paritytech/polkadot", branch = "master" } # Cumulus dependencies cumulus-client-consensus-common = { path = "../common" } cumulus-primitives-core = { path = "../../../primitives/core" } +cumulus-relay-chain-interface = { path = "../../relay-chain-interface" } # Other deps futures = { version = "0.3.8", features = ["compat"] } diff --git a/client/consensus/relay-chain/src/lib.rs b/client/consensus/relay-chain/src/lib.rs index 61eeba1c3b..7ab3ef2861 100644 --- a/client/consensus/relay-chain/src/lib.rs +++ b/client/consensus/relay-chain/src/lib.rs @@ -36,20 +36,16 @@ use cumulus_client_consensus_common::{ ParachainBlockImport, ParachainCandidate, ParachainConsensus, }; -use cumulus_primitives_core::{ - relay_chain::v1::{Block as PBlock, Hash as PHash, ParachainHost}, - ParaId, PersistedValidationData, -}; +use cumulus_primitives_core::{relay_chain::v1::Hash as PHash, ParaId, PersistedValidationData}; +use cumulus_relay_chain_interface::RelayChainInterface; use parking_lot::Mutex; -use polkadot_client::ClientHandle; -use sc_client_api::Backend; + use sc_consensus::{BlockImport, BlockImportParams}; -use sp_api::ProvideRuntimeApi; use sp_consensus::{ BlockOrigin, EnableProofRecording, Environment, ProofRecording, Proposal, Proposer, }; use sp_inherents::{CreateInherentDataProviders, InherentData, InherentDataProvider}; -use sp_runtime::traits::{Block as BlockT, HashFor, Header as HeaderT}; +use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; use std::{marker::PhantomData, sync::Arc, time::Duration}; mod import_queue; @@ -58,18 +54,18 @@ pub use import_queue::{import_queue, Verifier}; const LOG_TARGET: &str = "cumulus-consensus-relay-chain"; /// The implementation of the relay-chain provided consensus for parachains. -pub struct RelayChainConsensus { +pub struct RelayChainConsensus { para_id: ParaId, _phantom: PhantomData, proposer_factory: Arc>, create_inherent_data_providers: Arc, block_import: Arc>>, - relay_chain_client: Arc, - relay_chain_backend: Arc, + relay_chain_interface: RCInterface, } -impl Clone - for RelayChainConsensus +impl Clone for RelayChainConsensus +where + RCInterface: Clone, { fn clone(&self) -> Self { Self { @@ -78,18 +74,15 @@ impl Clone proposer_factory: self.proposer_factory.clone(), create_inherent_data_providers: self.create_inherent_data_providers.clone(), block_import: self.block_import.clone(), - relay_chain_backend: self.relay_chain_backend.clone(), - relay_chain_client: self.relay_chain_client.clone(), + relay_chain_interface: self.relay_chain_interface.clone(), } } } -impl RelayChainConsensus +impl RelayChainConsensus where B: BlockT, - RClient: ProvideRuntimeApi, - RClient::Api: ParachainHost, - RBackend: Backend, + RCInterface: RelayChainInterface, CIDP: CreateInherentDataProviders, { /// Create a new instance of relay-chain provided consensus. @@ -98,8 +91,7 @@ where proposer_factory: PF, create_inherent_data_providers: CIDP, block_import: BI, - polkadot_client: Arc, - polkadot_backend: Arc, + relay_chain_interface: RCInterface, ) -> Self { Self { para_id, @@ -108,8 +100,7 @@ where block_import: Arc::new(futures::lock::Mutex::new(ParachainBlockImport::new( block_import, ))), - relay_chain_backend: polkadot_backend, - relay_chain_client: polkadot_client, + relay_chain_interface, _phantom: PhantomData, } } @@ -148,13 +139,11 @@ where } #[async_trait::async_trait] -impl ParachainConsensus - for RelayChainConsensus +impl ParachainConsensus + for RelayChainConsensus where B: BlockT, - RClient: ProvideRuntimeApi + Send + Sync, - RClient::Api: ParachainHost, - RBackend: Backend, + RCInterface: RelayChainInterface + Clone, BI: BlockImport + Send + Sync, PF: Environment + Send + Sync, PF::Proposer: Proposer< @@ -229,27 +218,25 @@ where } /// Paramaters of [`build_relay_chain_consensus`]. -pub struct BuildRelayChainConsensusParams { +pub struct BuildRelayChainConsensusParams { pub para_id: ParaId, pub proposer_factory: PF, pub create_inherent_data_providers: CIDP, pub block_import: BI, - pub relay_chain_client: polkadot_client::Client, - pub relay_chain_backend: Arc, + pub relay_chain_interface: RCInterface, } /// Build the [`RelayChainConsensus`]. /// /// Returns a boxed [`ParachainConsensus`]. -pub fn build_relay_chain_consensus( +pub fn build_relay_chain_consensus( BuildRelayChainConsensusParams { para_id, proposer_factory, create_inherent_data_providers, block_import, - relay_chain_client, - relay_chain_backend, - }: BuildRelayChainConsensusParams, + relay_chain_interface, + }: BuildRelayChainConsensusParams, ) -> Box> where Block: BlockT, @@ -261,108 +248,14 @@ where Proof = ::Proof, >, BI: BlockImport + Send + Sync + 'static, - RBackend: Backend + 'static, CIDP: CreateInherentDataProviders + 'static, + RCInterface: RelayChainInterface + Clone + 'static, { - RelayChainConsensusBuilder::new( + Box::new(RelayChainConsensus::new( para_id, proposer_factory, - block_import, create_inherent_data_providers, - relay_chain_client, - relay_chain_backend, - ) - .build() -} - -/// Relay chain consensus builder. -/// -/// Builds a [`RelayChainConsensus`] for a parachain. As this requires -/// a concrete relay chain client instance, the builder takes a [`polkadot_client::Client`] -/// that wraps this concrete instanace. By using [`polkadot_client::ExecuteWithClient`] -/// the builder gets access to this concrete instance. -struct RelayChainConsensusBuilder { - para_id: ParaId, - _phantom: PhantomData, - proposer_factory: PF, - create_inherent_data_providers: CIDP, - block_import: BI, - relay_chain_backend: Arc, - relay_chain_client: polkadot_client::Client, -} - -impl RelayChainConsensusBuilder -where - Block: BlockT, - PF: Environment + Send + Sync + 'static, - PF::Proposer: Proposer< - Block, - Transaction = BI::Transaction, - ProofRecording = EnableProofRecording, - Proof = ::Proof, - >, - BI: BlockImport + Send + Sync + 'static, - RBackend: Backend + 'static, - CIDP: CreateInherentDataProviders + 'static, -{ - /// Create a new instance of the builder. - fn new( - para_id: ParaId, - proposer_factory: PF, - block_import: BI, - create_inherent_data_providers: CIDP, - relay_chain_client: polkadot_client::Client, - relay_chain_backend: Arc, - ) -> Self { - Self { - para_id, - _phantom: PhantomData, - proposer_factory, - block_import, - create_inherent_data_providers, - relay_chain_backend, - relay_chain_client, - } - } - - /// Build the relay chain consensus. - fn build(self) -> Box> { - self.relay_chain_client.clone().execute_with(self) - } -} - -impl polkadot_client::ExecuteWithClient - for RelayChainConsensusBuilder -where - Block: BlockT, - PF: Environment + Send + Sync + 'static, - PF::Proposer: Proposer< - Block, - Transaction = BI::Transaction, - ProofRecording = EnableProofRecording, - Proof = ::Proof, - >, - BI: BlockImport + Send + Sync + 'static, - RBackend: Backend + 'static, - CIDP: CreateInherentDataProviders + 'static, -{ - type Output = Box>; - - fn execute_with_client(self, client: Arc) -> Self::Output - where - >::StateBackend: sp_api::StateBackend>, - PBackend: Backend, - PBackend::State: sp_api::StateBackend, - Api: polkadot_client::RuntimeApiCollection, - PClient: polkadot_client::AbstractClient + 'static, - { - Box::new(RelayChainConsensus::new( - self.para_id, - self.proposer_factory, - self.create_inherent_data_providers, - self.block_import, - client.clone(), - self.relay_chain_backend, - )) - } + block_import, + relay_chain_interface, + )) } diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index ecdf4c9704..18a4a8c3a0 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -3,7 +3,7 @@ name = "cumulus-client-network" version = "0.1.0" authors = ["Parity Technologies "] description = "Cumulus-specific networking protocol" -edition = "2018" +edition = "2021" [dependencies] # Substrate deps @@ -13,20 +13,23 @@ sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-state-machine = { git = "https://github.com/paritytech/substrate", branch = "master" } # Polkadot deps polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "master" } polkadot-node-primitives = { git = "https://github.com/paritytech/polkadot", branch = "master" } -polkadot-client = { git = "https://github.com/paritytech/polkadot", branch = "master" } polkadot-parachain = { git = "https://github.com/paritytech/polkadot", branch = "master" } +cumulus-relay-chain-interface = { path = "../relay-chain-interface" } + # other deps codec = { package = "parity-scale-codec", version = "2.3.0", features = [ "derive" ] } futures = { version = "0.3.1", features = ["compat"] } futures-timer = "3.0.2" tracing = "0.1.22" -parking_lot = "0.10.2" +parking_lot = "0.11.1" derive_more = "0.99.2" +async-trait = "0.1.52" [dev-dependencies] tokio = { version = "1.10", features = ["macros"] } @@ -34,9 +37,12 @@ tokio = { version = "1.10", features = ["macros"] } # Cumulus deps cumulus-test-service = { path = "../../test/service" } cumulus-primitives-core = { path = "../../primitives/core" } +cumulus-relay-chain-local = { path = "../relay-chain-local" } # Polkadot deps polkadot-test-client = { git = "https://github.com/paritytech/polkadot", branch = "master" } +polkadot-client = { git = "https://github.com/paritytech/polkadot", branch = "master" } +polkadot-service = { git = "https://github.com/paritytech/polkadot", branch = "master" } # substrate deps sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/client/network/src/lib.rs b/client/network/src/lib.rs index e183fcd461..79e4f7c1b7 100644 --- a/client/network/src/lib.rs +++ b/client/network/src/lib.rs @@ -20,12 +20,8 @@ //! that use the relay chain provided consensus. See [`BlockAnnounceValidator`] //! and [`WaitToAnnounce`] for more information about this implementation. -use sc_client_api::{Backend, BlockchainEvents}; -use sp_api::ProvideRuntimeApi; -use sp_blockchain::HeaderBackend; -use sp_consensus::{ - block_validation::{BlockAnnounceValidator as BlockAnnounceValidatorT, Validation}, - SyncOracle, +use sp_consensus::block_validation::{ + BlockAnnounceValidator as BlockAnnounceValidatorT, Validation, }; use sp_core::traits::SpawnNamed; use sp_runtime::{ @@ -33,12 +29,12 @@ use sp_runtime::{ traits::{Block as BlockT, Header as HeaderT}, }; -use polkadot_client::ClientHandle; +use cumulus_relay_chain_interface::RelayChainInterface; use polkadot_node_primitives::{CollationSecondedSignal, Statement}; use polkadot_parachain::primitives::HeadData; use polkadot_primitives::v1::{ Block as PBlock, CandidateReceipt, CompactStatement, Hash as PHash, Id as ParaId, - OccupiedCoreAssumption, ParachainHost, SigningContext, UncheckedSigned, + OccupiedCoreAssumption, SigningContext, UncheckedSigned, }; use codec::{Decode, DecodeAll, Encode}; @@ -50,11 +46,8 @@ use futures::{ use std::{convert::TryFrom, fmt, marker::PhantomData, pin::Pin, sync::Arc}; -use wait_on_relay_chain_block::WaitOnRelayChainBlock; - #[cfg(test)] mod tests; -mod wait_on_relay_chain_block; const LOG_TARGET: &str = "sync::cumulus"; @@ -135,19 +128,18 @@ impl BlockAnnounceData { /// Check the signature of the statement. /// /// Returns an `Err(_)` if it failed. - fn check_signature

( + fn check_signature( self, - relay_chain_client: &Arc

, + relay_chain_client: &RCInterface, ) -> Result where - P: ProvideRuntimeApi + Send + Sync + 'static, - P::Api: ParachainHost, + RCInterface: RelayChainInterface + 'static, { - let runtime_api = relay_chain_client.runtime_api(); let validator_index = self.statement.unchecked_validator_index(); let runtime_api_block_id = BlockId::Hash(self.relay_parent); - let session_index = match runtime_api.session_index_for_child(&runtime_api_block_id) { + let session_index = match relay_chain_client.session_index_for_child(&runtime_api_block_id) + { Ok(r) => r, Err(e) => return Err(BlockAnnounceError(format!("{:?}", e))), }; @@ -155,7 +147,7 @@ impl BlockAnnounceData { let signing_context = SigningContext { parent_hash: self.relay_parent, session_index }; // Check that the signer is a legit validator. - let authorities = match runtime_api.validators(&runtime_api_block_id) { + let authorities = match relay_chain_client.validators(&runtime_api_block_id) { Ok(r) => r, Err(e) => return Err(BlockAnnounceError(format!("{:?}", e))), }; @@ -230,52 +222,37 @@ impl TryFrom<&'_ CollationSecondedSignal> for BlockAnnounceData { /// chain. If it is at the tip, it is required to provide a justification or otherwise we reject /// it. However, if the announcement is for a block below the tip the announcement is accepted /// as it probably comes from a node that is currently syncing the chain. -pub struct BlockAnnounceValidator { +pub struct BlockAnnounceValidator { phantom: PhantomData, - relay_chain_client: Arc, - relay_chain_backend: Arc, + relay_chain_interface: RCInterface, para_id: ParaId, - relay_chain_sync_oracle: Box, - wait_on_relay_chain_block: WaitOnRelayChainBlock, } -impl BlockAnnounceValidator { +impl BlockAnnounceValidator +where + RCInterface: Clone, +{ /// Create a new [`BlockAnnounceValidator`]. - pub fn new( - relay_chain_client: Arc, - para_id: ParaId, - relay_chain_sync_oracle: Box, - relay_chain_backend: Arc, - relay_chain_blockchain_events: Arc, - ) -> Self { + pub fn new(relay_chain_interface: RCInterface, para_id: ParaId) -> Self { Self { phantom: Default::default(), - relay_chain_client, + relay_chain_interface: relay_chain_interface.clone(), para_id, - relay_chain_sync_oracle, - relay_chain_backend: relay_chain_backend.clone(), - wait_on_relay_chain_block: WaitOnRelayChainBlock::new( - relay_chain_backend, - relay_chain_blockchain_events, - ), } } } -impl BlockAnnounceValidator +impl BlockAnnounceValidator where - R: ProvideRuntimeApi + Send + Sync + 'static, - R::Api: ParachainHost, - B: Backend + 'static, + RCInterface: RelayChainInterface + Clone, { /// Get the included block of the given parachain in the relay chain. fn included_block( - relay_chain_client: &R, + relay_chain_interface: &RCInterface, block_id: &BlockId, para_id: ParaId, ) -> Result { - let validation_data = relay_chain_client - .runtime_api() + let validation_data = relay_chain_interface .persisted_validation_data(block_id, para_id, OccupiedCoreAssumption::TimedOut) .map_err(|e| Box::new(BlockAnnounceError(format!("{:?}", e))) as Box<_>)? .ok_or_else(|| { @@ -293,12 +270,11 @@ where /// Get the backed block hash of the given parachain in the relay chain. fn backed_block_hash( - relay_chain_client: &R, + relay_chain_interface: &RCInterface, block_id: &BlockId, para_id: ParaId, ) -> Result, BoxedError> { - let candidate_receipt = relay_chain_client - .runtime_api() + let candidate_receipt = relay_chain_interface .candidate_pending_availability(block_id, para_id) .map_err(|e| Box::new(BlockAnnounceError(format!("{:?}", e))) as Box<_>)?; @@ -310,21 +286,20 @@ where &self, header: Block::Header, ) -> impl Future> { - let relay_chain_client = self.relay_chain_client.clone(); - let relay_chain_backend = self.relay_chain_backend.clone(); + let relay_chain_interface = self.relay_chain_interface.clone(); let para_id = self.para_id; async move { // Check if block is equal or higher than best (this requires a justification) - let relay_chain_info = relay_chain_backend.blockchain().info(); - let runtime_api_block_id = BlockId::Hash(relay_chain_info.best_hash); + let relay_chain_best_hash = relay_chain_interface.best_block_hash(); + let runtime_api_block_id = BlockId::Hash(relay_chain_best_hash); let block_number = header.number(); let best_head = - Self::included_block(&*relay_chain_client, &runtime_api_block_id, para_id)?; + Self::included_block(&relay_chain_interface, &runtime_api_block_id, para_id)?; let known_best_number = best_head.number(); let backed_block = - || Self::backed_block_hash(&*relay_chain_client, &runtime_api_block_id, para_id); + || Self::backed_block_hash(&relay_chain_interface, &runtime_api_block_id, para_id); if best_head == header { tracing::debug!(target: LOG_TARGET, "Announced block matches best block.",); @@ -348,20 +323,17 @@ where } } -impl BlockAnnounceValidatorT - for BlockAnnounceValidator +impl BlockAnnounceValidatorT + for BlockAnnounceValidator where - P: ProvideRuntimeApi + Send + Sync + 'static, - P::Api: ParachainHost, - B: Backend + 'static, - BCE: BlockchainEvents + 'static + Send + Sync, + RCInterface: RelayChainInterface + Clone + 'static, { fn validate( &mut self, header: &Block::Header, mut data: &[u8], ) -> Pin> + Send>> { - if self.relay_chain_sync_oracle.is_major_syncing() { + if self.relay_chain_interface.is_major_syncing() { return ready(Ok(Validation::Success { is_new_best: false })).boxed() } @@ -381,9 +353,8 @@ where .boxed(), }; - let relay_chain_client = self.relay_chain_client.clone(); + let relay_chain_interface = self.relay_chain_interface.clone(); let header_encoded = header.encode(); - let wait_on_relay_chain_block = self.wait_on_relay_chain_block.clone(); async move { if let Err(e) = block_announce_data.validate(header_encoded) { @@ -392,106 +363,19 @@ where let relay_parent = block_announce_data.receipt.descriptor.relay_parent; - wait_on_relay_chain_block - .wait_on_relay_chain_block(relay_parent) + relay_chain_interface + .wait_for_block(relay_parent) .await .map_err(|e| Box::new(BlockAnnounceError(e.to_string())) as Box<_>)?; block_announce_data - .check_signature(&relay_chain_client) + .check_signature(&relay_chain_interface) .map_err(|e| Box::new(e) as Box<_>) } .boxed() } } -/// Build a block announce validator instance. -/// -/// Returns a boxed [`BlockAnnounceValidator`]. -pub fn build_block_announce_validator( - relay_chain_client: polkadot_client::Client, - para_id: ParaId, - relay_chain_sync_oracle: Box, - relay_chain_backend: Arc, -) -> Box + Send> -where - B: Backend + Send + 'static, -{ - BlockAnnounceValidatorBuilder::new( - relay_chain_client, - para_id, - relay_chain_sync_oracle, - relay_chain_backend, - ) - .build() -} - -/// Block announce validator builder. -/// -/// Builds a [`BlockAnnounceValidator`] for a parachain. As this requires -/// a concrete relay chain client instance, the builder takes a [`polkadot_client::Client`] -/// that wraps this concrete instanace. By using [`polkadot_client::ExecuteWithClient`] -/// the builder gets access to this concrete instance. -struct BlockAnnounceValidatorBuilder { - phantom: PhantomData, - relay_chain_client: polkadot_client::Client, - para_id: ParaId, - relay_chain_sync_oracle: Box, - relay_chain_backend: Arc, -} - -impl BlockAnnounceValidatorBuilder -where - B: Backend + Send + 'static, -{ - /// Create a new instance of the builder. - fn new( - relay_chain_client: polkadot_client::Client, - para_id: ParaId, - relay_chain_sync_oracle: Box, - relay_chain_backend: Arc, - ) -> Self { - Self { - relay_chain_client, - para_id, - relay_chain_sync_oracle, - relay_chain_backend, - phantom: PhantomData, - } - } - - /// Build the block announce validator. - fn build(self) -> Box + Send> { - self.relay_chain_client.clone().execute_with(self) - } -} - -impl polkadot_client::ExecuteWithClient - for BlockAnnounceValidatorBuilder -where - B: Backend + Send + 'static, -{ - type Output = Box + Send>; - - fn execute_with_client(self, client: Arc) -> Self::Output - where - >::StateBackend: - sp_api::StateBackend, - PBackend: Backend, - PBackend::State: sp_api::StateBackend, - Api: polkadot_client::RuntimeApiCollection, - PClient: polkadot_client::AbstractClient + 'static, - { - Box::new(BlockAnnounceValidator::new( - client.clone(), - self.para_id, - self.relay_chain_sync_oracle, - self.relay_chain_backend, - client, - )) - } -} - /// Wait before announcing a block that a candidate message has been received for this block, then /// add this message as justification for the block announcement. /// @@ -522,6 +406,7 @@ impl WaitToAnnounce { self.spawner.spawn( "cumulus-wait-to-announce", + None, async move { tracing::debug!( target: "cumulus-network", diff --git a/client/network/src/tests.rs b/client/network/src/tests.rs index 7124ebca85..34584edd69 100644 --- a/client/network/src/tests.rs +++ b/client/network/src/tests.rs @@ -15,29 +15,33 @@ // along with Polkadot. If not, see . use super::*; +use async_trait::async_trait; +use cumulus_relay_chain_interface::WaitError; +use cumulus_relay_chain_local::{check_block_in_chain, BlockCheckStatus}; use cumulus_test_service::runtime::{Block, Hash, Header}; -use futures::{executor::block_on, poll, task::Poll}; +use futures::{executor::block_on, poll, task::Poll, FutureExt, StreamExt}; use parking_lot::Mutex; use polkadot_node_primitives::{SignedFullStatement, Statement}; use polkadot_primitives::v1::{ - Block as PBlock, BlockNumber, CandidateCommitments, CandidateDescriptor, CandidateEvent, - CommittedCandidateReceipt, CoreState, GroupRotationInfo, Hash as PHash, HeadData, Id as ParaId, - InboundDownwardMessage, InboundHrmpMessage, OccupiedCoreAssumption, ParachainHost, - PersistedValidationData, ScrapedOnChainVotes, SessionIndex, SessionInfo, SigningContext, - ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, + Block as PBlock, CandidateCommitments, CandidateDescriptor, CollatorPair, + CommittedCandidateReceipt, Hash as PHash, HeadData, Id as ParaId, InboundDownwardMessage, + InboundHrmpMessage, OccupiedCoreAssumption, PersistedValidationData, SessionIndex, + SigningContext, ValidationCodeHash, ValidatorId, }; +use polkadot_service::Handle; use polkadot_test_client::{ Client as PClient, ClientBlockImportExt, DefaultTestClientBuilderExt, FullBackend as PBackend, InitPolkadotBlockBuilder, TestClientBuilder, TestClientBuilderExt, }; -use sp_api::{ApiRef, ProvideRuntimeApi}; +use sc_client_api::{Backend, BlockchainEvents}; use sp_blockchain::HeaderBackend; use sp_consensus::BlockOrigin; -use sp_core::H256; +use sp_core::{Pair, H256}; use sp_keyring::Sr25519Keyring; use sp_keystore::{testing::KeyStore, SyncCryptoStore, SyncCryptoStorePtr}; use sp_runtime::RuntimeAppPublic; -use std::collections::BTreeMap; +use sp_state_machine::StorageValue; +use std::{collections::BTreeMap, time::Duration}; fn check_error(error: crate::BoxedError, check_error: impl Fn(&BlockAnnounceError) -> bool) { let error = *error @@ -49,31 +53,190 @@ fn check_error(error: crate::BoxedError, check_error: impl Fn(&BlockAnnounceErro } #[derive(Clone)] -struct DummyCollatorNetwork; +struct DummyRelayChainInterface { + data: Arc>, + relay_client: Arc, + relay_backend: Arc, +} -impl SyncOracle for DummyCollatorNetwork { - fn is_major_syncing(&mut self) -> bool { +impl DummyRelayChainInterface { + fn new() -> Self { + let builder = TestClientBuilder::new(); + let relay_backend = builder.backend(); + + Self { + data: Arc::new(Mutex::new(ApiData { + validators: vec![Sr25519Keyring::Alice.public().into()], + has_pending_availability: false, + })), + relay_client: Arc::new(builder.build()), + relay_backend, + } + } +} + +#[async_trait] +impl RelayChainInterface for DummyRelayChainInterface { + fn validators( + &self, + _: &cumulus_primitives_core::relay_chain::BlockId, + ) -> Result, sp_api::ApiError> { + Ok(self.data.lock().validators.clone()) + } + + fn block_status( + &self, + block_id: cumulus_primitives_core::relay_chain::BlockId, + ) -> Result { + self.relay_backend.blockchain().status(block_id) + } + + fn best_block_hash(&self) -> PHash { + self.relay_backend.blockchain().info().best_hash + } + + fn retrieve_dmq_contents(&self, _: ParaId, _: PHash) -> Option> { + unimplemented!("Not needed for test") + } + + fn retrieve_all_inbound_hrmp_channel_contents( + &self, + _: ParaId, + _: PHash, + ) -> Option>> { + Some(BTreeMap::new()) + } + + fn persisted_validation_data( + &self, + _: &cumulus_primitives_core::relay_chain::BlockId, + _: ParaId, + _: OccupiedCoreAssumption, + ) -> Result, sp_api::ApiError> { + Ok(Some(PersistedValidationData { + parent_head: HeadData(default_header().encode()), + ..Default::default() + })) + } + + fn candidate_pending_availability( + &self, + _: &cumulus_primitives_core::relay_chain::BlockId, + _: ParaId, + ) -> Result, sp_api::ApiError> { + if self.data.lock().has_pending_availability { + Ok(Some(CommittedCandidateReceipt { + descriptor: CandidateDescriptor { + para_head: polkadot_parachain::primitives::HeadData(default_header().encode()) + .hash(), + para_id: 0u32.into(), + relay_parent: PHash::random(), + collator: CollatorPair::generate().0.public(), + persisted_validation_data_hash: PHash::random().into(), + pov_hash: PHash::random(), + erasure_root: PHash::random(), + signature: sp_core::sr25519::Signature([0u8; 64]).into(), + validation_code_hash: ValidationCodeHash::from(PHash::random()), + }, + commitments: CandidateCommitments { + upward_messages: Vec::new(), + horizontal_messages: Vec::new(), + new_validation_code: None, + head_data: HeadData(Vec::new()), + processed_downward_messages: 0, + hrmp_watermark: 0, + }, + })) + } else { + Ok(None) + } + } + + fn session_index_for_child( + &self, + _: &cumulus_primitives_core::relay_chain::BlockId, + ) -> Result { + Ok(0) + } + + fn import_notification_stream(&self) -> sc_client_api::ImportNotifications { + self.relay_client.import_notification_stream() + } + + fn finality_notification_stream(&self) -> sc_client_api::FinalityNotifications { + self.relay_client.finality_notification_stream() + } + + fn storage_changes_notification_stream( + &self, + filter_keys: Option<&[sc_client_api::StorageKey]>, + child_filter_keys: Option< + &[(sc_client_api::StorageKey, Option>)], + >, + ) -> sc_client_api::blockchain::Result> { + self.relay_client + .storage_changes_notification_stream(filter_keys, child_filter_keys) + } + + fn is_major_syncing(&self) -> bool { false } - fn is_offline(&mut self) -> bool { - unimplemented!("Not required in tests") + fn overseer_handle(&self) -> Option { + unimplemented!("Not needed for test") + } + + fn get_storage_by_key( + &self, + _: &polkadot_service::BlockId, + _: &[u8], + ) -> Result, sp_blockchain::Error> { + unimplemented!("Not needed for test") + } + + fn prove_read( + &self, + _: &polkadot_service::BlockId, + _: &Vec>, + ) -> Result, Box> { + unimplemented!("Not needed for test") + } + + async fn wait_for_block( + &self, + hash: PHash, + ) -> Result<(), cumulus_relay_chain_interface::WaitError> { + let mut listener = match check_block_in_chain( + self.relay_backend.clone(), + self.relay_client.clone(), + hash, + )? { + BlockCheckStatus::InChain => return Ok(()), + BlockCheckStatus::Unknown(listener) => listener, + }; + + let mut timeout = futures_timer::Delay::new(Duration::from_secs(10)).fuse(); + + loop { + futures::select! { + _ = timeout => return Err(WaitError::Timeout(hash)), + evt = listener.next() => match evt { + Some(evt) if evt.hash == hash => return Ok(()), + // Not the event we waited on. + Some(_) => continue, + None => return Err(WaitError::ImportListenerClosed(hash)), + } + } + } } } fn make_validator_and_api( -) -> (BlockAnnounceValidator, Arc) { - let api = Arc::new(TestApi::new()); - +) -> (BlockAnnounceValidator>, Arc) { + let relay_chain_interface = Arc::new(DummyRelayChainInterface::new()); ( - BlockAnnounceValidator::new( - api.clone(), - ParaId::from(56), - Box::new(DummyCollatorNetwork), - api.relay_backend.clone(), - api.relay_client.clone(), - ), - api, + BlockAnnounceValidator::new(relay_chain_interface.clone(), ParaId::from(56)), + relay_chain_interface, ) } @@ -89,7 +252,7 @@ fn default_header() -> Header { /// Same as [`make_gossip_message_and_header`], but using the genesis header as relay parent. async fn make_gossip_message_and_header_using_genesis( - api: Arc, + api: Arc, validator_index: u32, ) -> (CollationSecondedSignal, Header) { let relay_parent = api.relay_client.hash(0).ok().flatten().expect("Genesis hash exists"); @@ -98,7 +261,7 @@ async fn make_gossip_message_and_header_using_genesis( } async fn make_gossip_message_and_header( - api: Arc, + relay_chain_interface: Arc, relay_parent: H256, validator_index: u32, ) -> (CollationSecondedSignal, Header) { @@ -109,8 +272,9 @@ async fn make_gossip_message_and_header( Some(&Sr25519Keyring::Alice.to_seed()), ) .unwrap(); - let session_index = - api.runtime_api().session_index_for_child(&BlockId::Hash(relay_parent)).unwrap(); + let session_index = relay_chain_interface + .session_index_for_child(&BlockId::Hash(relay_parent)) + .unwrap(); let signing_context = SigningContext { parent_hash: relay_parent, session_index }; let header = default_header(); @@ -120,9 +284,15 @@ async fn make_gossip_message_and_header( ..Default::default() }, descriptor: CandidateDescriptor { + para_id: 0u32.into(), relay_parent, + collator: CollatorPair::generate().0.public(), + persisted_validation_data_hash: PHash::random().into(), + pov_hash: PHash::random(), + erasure_root: PHash::random(), + signature: sp_core::sr25519::Signature([0u8; 64]).into(), para_head: polkadot_parachain::primitives::HeadData(header.encode()).hash(), - ..Default::default() + validation_code_hash: ValidationCodeHash::from(PHash::random()), }, }; let statement = Statement::Seconded(candidate_receipt); @@ -285,8 +455,7 @@ fn check_statement_seconded() { Some(&Sr25519Keyring::Alice.to_seed()), ) .unwrap(); - let session_index = - api.runtime_api().session_index_for_child(&BlockId::Hash(relay_parent)).unwrap(); + let session_index = api.session_index_for_child(&BlockId::Hash(relay_parent)).unwrap(); let signing_context = SigningContext { parent_hash: relay_parent, session_index }; let statement = Statement::Valid(Default::default()); @@ -303,7 +472,20 @@ fn check_statement_seconded() { .expect("Signs statement"); let data = BlockAnnounceData { - receipt: Default::default(), + receipt: CandidateReceipt { + commitments_hash: PHash::random(), + descriptor: CandidateDescriptor { + para_head: HeadData(Vec::new()).hash(), + para_id: 0u32.into(), + relay_parent: PHash::random(), + collator: CollatorPair::generate().0.public(), + persisted_validation_data_hash: PHash::random().into(), + pov_hash: PHash::random(), + erasure_root: PHash::random(), + signature: sp_core::sr25519::Signature([0u8; 64]).into(), + validation_code_hash: ValidationCodeHash::from(PHash::random()), + }, + }, statement: signed_statement.convert_payload().into(), relay_parent, } @@ -377,126 +559,3 @@ struct ApiData { validators: Vec, has_pending_availability: bool, } - -struct TestApi { - data: Arc>, - relay_client: Arc, - relay_backend: Arc, -} - -impl TestApi { - fn new() -> Self { - let builder = TestClientBuilder::new(); - let relay_backend = builder.backend(); - - Self { - data: Arc::new(Mutex::new(ApiData { - validators: vec![Sr25519Keyring::Alice.public().into()], - has_pending_availability: false, - })), - relay_client: Arc::new(builder.build()), - relay_backend, - } - } -} - -#[derive(Default)] -struct RuntimeApi { - data: Arc>, -} - -impl ProvideRuntimeApi for TestApi { - type Api = RuntimeApi; - - fn runtime_api<'a>(&'a self) -> ApiRef<'a, Self::Api> { - RuntimeApi { data: self.data.clone() }.into() - } -} - -sp_api::mock_impl_runtime_apis! { - impl ParachainHost for RuntimeApi { - fn validators(&self) -> Vec { - self.data.lock().validators.clone() - } - - fn validator_groups(&self) -> (Vec>, GroupRotationInfo) { - (Vec::new(), GroupRotationInfo { session_start_block: 0, group_rotation_frequency: 0, now: 0 }) - } - - fn availability_cores(&self) -> Vec> { - Vec::new() - } - - fn persisted_validation_data( - &self, - _: ParaId, - _: OccupiedCoreAssumption, - ) -> Option> { - Some(PersistedValidationData { - parent_head: HeadData(default_header().encode()), - ..Default::default() - }) - } - - fn session_index_for_child(&self) -> SessionIndex { - 0 - } - - fn validation_code(&self, _: ParaId, _: OccupiedCoreAssumption) -> Option { - None - } - - fn candidate_pending_availability(&self, _: ParaId) -> Option> { - if self.data.lock().has_pending_availability { - Some(CommittedCandidateReceipt { - descriptor: CandidateDescriptor { - para_head: polkadot_parachain::primitives::HeadData( - default_header().encode(), - ).hash(), - ..Default::default() - }, - ..Default::default() - }) - } else { - None - } - } - - fn candidate_events(&self) -> Vec> { - Vec::new() - } - - fn session_info(_: SessionIndex) -> Option { - None - } - - fn check_validation_outputs(_: ParaId, _: CandidateCommitments) -> bool { - false - } - - fn dmq_contents(_: ParaId) -> Vec> { - Vec::new() - } - - fn inbound_hrmp_channels_contents( - _: ParaId, - ) -> BTreeMap>> { - BTreeMap::new() - } - - fn assumed_validation_data( - _: ParaId, - _: Hash, - ) -> Option<(PersistedValidationData, ValidationCodeHash)> { - None - } - - fn validation_code_by_hash(_: ValidationCodeHash) -> Option { - None - } - - fn on_chain_votes() -> Option> { - None - } - } -} diff --git a/client/network/src/wait_on_relay_chain_block.rs b/client/network/src/wait_on_relay_chain_block.rs deleted file mode 100644 index 5bb086fba8..0000000000 --- a/client/network/src/wait_on_relay_chain_block.rs +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright 2020-2021 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 . - -//! Provides the [`WaitOnRelayChainBlock`] type. - -use futures::{future::ready, Future, FutureExt, StreamExt}; -use polkadot_primitives::v1::{Block as PBlock, Hash as PHash}; -use sc_client_api::{ - blockchain::{self, BlockStatus, HeaderBackend}, - Backend, BlockchainEvents, -}; -use sp_runtime::generic::BlockId; -use std::{sync::Arc, time::Duration}; - -/// The timeout in seconds after that the waiting for a block should be aborted. -const TIMEOUT_IN_SECONDS: u64 = 6; - -/// Custom error type used by [`WaitOnRelayChainBlock`]. -#[derive(Debug, derive_more::Display)] -pub enum Error { - #[display(fmt = "Timeout while waiting for relay-chain block `{}` to be imported.", _0)] - Timeout(PHash), - #[display( - fmt = "Import listener closed while waiting for relay-chain block `{}` to be imported.", - _0 - )] - ImportListenerClosed(PHash), - #[display( - fmt = "Blockchain returned an error while waiting for relay-chain block `{}` to be imported: {:?}", - _0, - _1 - )] - BlockchainError(PHash, blockchain::Error), -} - -/// A helper to wait for a given relay chain block in an async way. -/// -/// The caller needs to pass the hash of a block it waits for and the function will return when the -/// block is available or an error occurred. -/// -/// The waiting for the block is implemented as follows: -/// -/// 1. Get a read lock on the import lock from the backend. -/// -/// 2. Check if the block is already imported. If yes, return from the function. -/// -/// 3. If the block isn't imported yet, add an import notification listener. -/// -/// 4. Poll the import notification listener until the block is imported or the timeout is fired. -/// -/// The timeout is set to 6 seconds. This should be enough time to import the block in the current -/// round and if not, the new round of the relay chain already started anyway. -pub struct WaitOnRelayChainBlock { - block_chain_events: Arc, - backend: Arc, -} - -impl Clone for WaitOnRelayChainBlock { - fn clone(&self) -> Self { - Self { backend: self.backend.clone(), block_chain_events: self.block_chain_events.clone() } - } -} - -impl WaitOnRelayChainBlock { - /// Creates a new instance of `Self`. - pub fn new(backend: Arc, block_chain_events: Arc) -> Self { - Self { backend, block_chain_events } - } -} - -impl WaitOnRelayChainBlock -where - B: Backend, - BCE: BlockchainEvents, -{ - pub fn wait_on_relay_chain_block( - &self, - hash: PHash, - ) -> impl Future> { - let _lock = self.backend.get_import_lock().read(); - match self.backend.blockchain().status(BlockId::Hash(hash)) { - Ok(BlockStatus::InChain) => return ready(Ok(())).boxed(), - Err(err) => return ready(Err(Error::BlockchainError(hash, err))).boxed(), - _ => {}, - } - - let mut listener = self.block_chain_events.import_notification_stream(); - // Now it is safe to drop the lock, even when the block is now imported, it should show - // up in our registered listener. - drop(_lock); - - let mut timeout = futures_timer::Delay::new(Duration::from_secs(TIMEOUT_IN_SECONDS)).fuse(); - - async move { - loop { - futures::select! { - _ = timeout => return Err(Error::Timeout(hash)), - evt = listener.next() => match evt { - Some(evt) if evt.hash == hash => return Ok(()), - // Not the event we waited on. - Some(_) => continue, - None => return Err(Error::ImportListenerClosed(hash)), - } - } - } - } - .boxed() - } -} - -#[cfg(test)] -mod tests { - use super::*; - - use polkadot_test_client::{ - construct_transfer_extrinsic, BlockBuilderExt, Client, ClientBlockImportExt, - DefaultTestClientBuilderExt, ExecutionStrategy, FullBackend, InitPolkadotBlockBuilder, - TestClientBuilder, TestClientBuilderExt, - }; - use sp_consensus::BlockOrigin; - use sp_runtime::traits::Block as BlockT; - - use futures::{executor::block_on, poll, task::Poll}; - - fn build_client_backend_and_block() -> (Arc, Arc, PBlock) { - let builder = - TestClientBuilder::new().set_execution_strategy(ExecutionStrategy::NativeWhenPossible); - let backend = builder.backend(); - let client = Arc::new(builder.build()); - - let block_builder = client.init_polkadot_block_builder(); - let block = block_builder.build().expect("Finalizes the block").block; - - (client, backend, block) - } - - #[test] - fn returns_directly_for_available_block() { - let (mut client, backend, block) = build_client_backend_and_block(); - let hash = block.hash(); - - block_on(client.import(BlockOrigin::Own, block)).expect("Imports the block"); - - let wait = WaitOnRelayChainBlock::new(backend, client); - - block_on(async move { - // Should be ready on the first poll - assert!(matches!(poll!(wait.wait_on_relay_chain_block(hash)), Poll::Ready(Ok(())))); - }); - } - - #[test] - fn resolve_after_block_import_notification_was_received() { - let (mut client, backend, block) = build_client_backend_and_block(); - let hash = block.hash(); - - let wait = WaitOnRelayChainBlock::new(backend, client.clone()); - - block_on(async move { - let mut future = wait.wait_on_relay_chain_block(hash); - // As the block is not yet imported, the first poll should return `Pending` - assert!(poll!(&mut future).is_pending()); - - // Import the block that should fire the notification - client.import(BlockOrigin::Own, block).await.expect("Imports the block"); - - // Now it should have received the notification and report that the block was imported - assert!(matches!(poll!(future), Poll::Ready(Ok(())))); - }); - } - - #[test] - fn wait_for_block_time_out_when_block_is_not_imported() { - let (client, backend, block) = build_client_backend_and_block(); - let hash = block.hash(); - - let wait = WaitOnRelayChainBlock::new(backend, client.clone()); - - assert!(matches!(block_on(wait.wait_on_relay_chain_block(hash)), Err(Error::Timeout(_)))); - } - - #[test] - fn do_not_resolve_after_different_block_import_notification_was_received() { - let (mut client, backend, block) = build_client_backend_and_block(); - let hash = block.hash(); - - let ext = construct_transfer_extrinsic( - &*client, - sp_keyring::Sr25519Keyring::Alice, - sp_keyring::Sr25519Keyring::Bob, - 1000, - ); - let mut block_builder = client.init_polkadot_block_builder(); - // Push an extrinsic to get a different block hash. - block_builder.push_polkadot_extrinsic(ext).expect("Push extrinsic"); - let block2 = block_builder.build().expect("Build second block").block; - let hash2 = block2.hash(); - - let wait = WaitOnRelayChainBlock::new(backend, client.clone()); - - block_on(async move { - let mut future = wait.wait_on_relay_chain_block(hash); - let mut future2 = wait.wait_on_relay_chain_block(hash2); - // As the block is not yet imported, the first poll should return `Pending` - assert!(poll!(&mut future).is_pending()); - assert!(poll!(&mut future2).is_pending()); - - // Import the block that should fire the notification - client.import(BlockOrigin::Own, block2).await.expect("Imports the second block"); - - // The import notification of the second block should not make this one finish - assert!(poll!(&mut future).is_pending()); - // Now it should have received the notification and report that the block was imported - assert!(matches!(poll!(future2), Poll::Ready(Ok(())))); - - client.import(BlockOrigin::Own, block).await.expect("Imports the first block"); - - // Now it should be ready - assert!(matches!(poll!(future), Poll::Ready(Ok(())))); - }); - } -} diff --git a/client/network/tests/sync.rs b/client/network/tests/sync.rs index 56f5bc3a72..1ab1d4399b 100644 --- a/client/network/tests/sync.rs +++ b/client/network/tests/sync.rs @@ -16,7 +16,6 @@ use cumulus_primitives_core::ParaId; use cumulus_test_service::{initial_head_data, run_relay_chain_validator_node, Keyring::*}; -use futures::join; #[substrate_test_utils::test] #[ignore] @@ -29,7 +28,7 @@ async fn sync_blocks_from_tip_without_being_connected_to_a_collator() { let tokio_handle = tokio::runtime::Handle::current(); // start alice - let alice = run_relay_chain_validator_node(tokio_handle.clone(), Alice, || {}, vec![]); + let alice = run_relay_chain_validator_node(tokio_handle.clone(), Alice, || {}, Vec::new()); // start bob let bob = @@ -71,12 +70,4 @@ async fn sync_blocks_from_tip_without_being_connected_to_a_collator() { .await; eve.wait_for_blocks(7).await; - - join!( - alice.task_manager.clean_shutdown(), - bob.task_manager.clean_shutdown(), - charlie.task_manager.clean_shutdown(), - dave.task_manager.clean_shutdown(), - eve.task_manager.clean_shutdown(), - ); } diff --git a/client/pov-recovery/Cargo.toml b/client/pov-recovery/Cargo.toml index 31b96d0e4b..1c2c757209 100644 --- a/client/pov-recovery/Cargo.toml +++ b/client/pov-recovery/Cargo.toml @@ -3,7 +3,7 @@ name = "cumulus-client-pov-recovery" version = "0.1.0" authors = ["Parity Technologies "] description = "Cumulus-specific networking protocol" -edition = "2018" +edition = "2021" [dependencies] # Substrate deps @@ -22,6 +22,7 @@ polkadot-node-subsystem = { git = "https://github.com/paritytech/polkadot", bran # Cumulus deps cumulus-primitives-core = { path = "../../primitives/core" } +cumulus-relay-chain-interface = {path = "../relay-chain-interface"} # other deps codec = { package = "parity-scale-codec", version = "2.3.0", features = [ "derive" ] } diff --git a/client/pov-recovery/src/lib.rs b/client/pov-recovery/src/lib.rs index a875a5c6eb..7e31f5000d 100644 --- a/client/pov-recovery/src/lib.rs +++ b/client/pov-recovery/src/lib.rs @@ -44,7 +44,6 @@ use sc_client_api::{BlockBackend, BlockchainEvents, UsageProvider}; use sc_consensus::import_queue::{ImportQueue, IncomingBlock}; -use sp_api::ProvideRuntimeApi; use sp_consensus::{BlockOrigin, BlockStatus}; use sp_runtime::{ generic::BlockId, @@ -54,11 +53,11 @@ use sp_runtime::{ use polkadot_node_primitives::{AvailableData, POV_BOMB_LIMIT}; use polkadot_overseer::Handle as OverseerHandle; use polkadot_primitives::v1::{ - Block as PBlock, CandidateReceipt, CommittedCandidateReceipt, Id as ParaId, ParachainHost, - SessionIndex, + CandidateReceipt, CommittedCandidateReceipt, Id as ParaId, SessionIndex, }; use cumulus_primitives_core::ParachainBlockData; +use cumulus_relay_chain_interface::RelayChainInterface; use codec::Decode; use futures::{select, stream::FuturesUnordered, Future, FutureExt, Stream, StreamExt}; @@ -102,15 +101,14 @@ pub struct PoVRecovery { relay_chain_slot_duration: Duration, parachain_client: Arc, parachain_import_queue: IQ, - relay_chain_client: Arc, + relay_chain_interface: RC, para_id: ParaId, } -impl PoVRecovery +impl PoVRecovery where PC: BlockBackend + BlockchainEvents + UsageProvider, - RC: ProvideRuntimeApi + BlockchainEvents, - RC::Api: ParachainHost, + RCInterface: RelayChainInterface + Clone, IQ: ImportQueue, { /// Create a new instance. @@ -119,7 +117,7 @@ where relay_chain_slot_duration: Duration, parachain_client: Arc, parachain_import_queue: IQ, - relay_chain_client: Arc, + relay_chain_interface: RCInterface, para_id: ParaId, ) -> Self { Self { @@ -130,7 +128,7 @@ where waiting_for_parent: HashMap::new(), parachain_client, parachain_import_queue, - relay_chain_client, + relay_chain_interface, para_id, } } @@ -365,7 +363,7 @@ where let mut imported_blocks = self.parachain_client.import_notification_stream().fuse(); let mut finalized_blocks = self.parachain_client.finality_notification_stream().fuse(); let pending_candidates = - pending_candidates(self.relay_chain_client.clone(), self.para_id).fuse(); + pending_candidates(self.relay_chain_interface.clone(), self.para_id).fuse(); futures::pin_mut!(pending_candidates); loop { @@ -419,20 +417,15 @@ where } /// Returns a stream over pending candidates for the parachain corresponding to `para_id`. -fn pending_candidates( - relay_chain_client: Arc, +fn pending_candidates( + relay_chain_client: impl RelayChainInterface, para_id: ParaId, -) -> impl Stream -where - RC: ProvideRuntimeApi + BlockchainEvents, - RC::Api: ParachainHost, -{ +) -> impl Stream { relay_chain_client.import_notification_stream().filter_map(move |n| { - let runtime_api = relay_chain_client.runtime_api(); - let res = runtime_api + let res = relay_chain_client .candidate_pending_availability(&BlockId::hash(n.hash), para_id) .and_then(|pa| { - runtime_api + relay_chain_client .session_index_for_child(&BlockId::hash(n.hash)) .map(|v| pa.map(|pa| (pa, v))) }) diff --git a/client/pov-recovery/tests/pov_recovery.rs b/client/pov-recovery/tests/pov_recovery.rs index bbad4b2416..c0240a48b9 100644 --- a/client/pov-recovery/tests/pov_recovery.rs +++ b/client/pov-recovery/tests/pov_recovery.rs @@ -16,7 +16,6 @@ use cumulus_primitives_core::ParaId; use cumulus_test_service::{initial_head_data, Keyring::*}; -use futures::join; use std::sync::Arc; /// Tests the PoV recovery. @@ -39,7 +38,7 @@ async fn pov_recovery() { tokio_handle.clone(), Alice, || {}, - vec![], + Vec::new(), ); // Start bob @@ -86,11 +85,4 @@ async fn pov_recovery() { .await; dave.wait_for_blocks(7).await; - - join!( - alice.task_manager.clean_shutdown(), - bob.task_manager.clean_shutdown(), - charlie.task_manager.clean_shutdown(), - dave.task_manager.clean_shutdown(), - ); } diff --git a/client/relay-chain-interface/Cargo.toml b/client/relay-chain-interface/Cargo.toml new file mode 100644 index 0000000000..a962155ed1 --- /dev/null +++ b/client/relay-chain-interface/Cargo.toml @@ -0,0 +1,21 @@ +[package] +authors = ["Parity Technologies "] +name = "cumulus-relay-chain-interface" +version = "0.1.0" +edition = "2021" + +[dependencies] +polkadot-overseer = { git = "https://github.com/paritytech/polkadot", branch = "master" } + +cumulus-primitives-core = { path = "../../primitives/core" } + +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-state-machine = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" } + +parking_lot = "0.11.1" +derive_more = "0.99.2" +async-trait = "0.1.52" diff --git a/client/relay-chain-interface/src/lib.rs b/client/relay-chain-interface/src/lib.rs new file mode 100644 index 0000000000..185e9a6f0a --- /dev/null +++ b/client/relay-chain-interface/src/lib.rs @@ -0,0 +1,248 @@ +// Copyright 2021 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 std::{collections::BTreeMap, sync::Arc}; + +use cumulus_primitives_core::{ + relay_chain::{ + v1::{CommittedCandidateReceipt, OccupiedCoreAssumption, SessionIndex, ValidatorId}, + Block as PBlock, BlockId, Hash as PHash, InboundHrmpMessage, + }, + InboundDownwardMessage, ParaId, PersistedValidationData, +}; +use polkadot_overseer::Handle as OverseerHandle; +use sc_client_api::{blockchain::BlockStatus, StorageProof}; + +use sp_api::ApiError; +use sp_state_machine::StorageValue; + +use async_trait::async_trait; + +#[derive(Debug, derive_more::Display)] +pub enum WaitError { + #[display(fmt = "Timeout while waiting for relay-chain block `{}` to be imported.", _0)] + Timeout(PHash), + #[display( + fmt = "Import listener closed while waiting for relay-chain block `{}` to be imported.", + _0 + )] + ImportListenerClosed(PHash), + #[display( + fmt = "Blockchain returned an error while waiting for relay-chain block `{}` to be imported: {:?}", + _0, + _1 + )] + BlockchainError(PHash, sp_blockchain::Error), +} + +/// Trait that provides all necessary methods for interaction between collator and relay chain. +#[async_trait] +pub trait RelayChainInterface: Send + Sync { + /// Fetch a storage item by key. + fn get_storage_by_key( + &self, + block_id: &BlockId, + key: &[u8], + ) -> Result, sp_blockchain::Error>; + + /// Fetch a vector of current validators. + fn validators(&self, block_id: &BlockId) -> Result, ApiError>; + + /// Get the status of a given block. + fn block_status(&self, block_id: BlockId) -> Result; + + /// Get the hash of the current best block. + fn best_block_hash(&self) -> PHash; + + /// Returns the whole contents of the downward message queue for the parachain we are collating + /// for. + /// + /// Returns `None` in case of an error. + fn retrieve_dmq_contents( + &self, + para_id: ParaId, + relay_parent: PHash, + ) -> Option>; + + /// Returns channels contents for each inbound HRMP channel addressed to the parachain we are + /// collating for. + /// + /// Empty channels are also included. + fn retrieve_all_inbound_hrmp_channel_contents( + &self, + para_id: ParaId, + relay_parent: PHash, + ) -> Option>>; + + /// Yields the persisted validation data for the given `ParaId` along with an assumption that + /// should be used if the para currently occupies a core. + /// + /// Returns `None` if either the para is not registered or the assumption is `Freed` + /// and the para already occupies a core. + fn persisted_validation_data( + &self, + block_id: &BlockId, + para_id: ParaId, + _: OccupiedCoreAssumption, + ) -> Result, ApiError>; + + /// Get the receipt of a candidate pending availability. This returns `Some` for any paras + /// assigned to occupied cores in `availability_cores` and `None` otherwise. + fn candidate_pending_availability( + &self, + block_id: &BlockId, + para_id: ParaId, + ) -> Result, ApiError>; + + /// Returns the session index expected at a child of the block. + fn session_index_for_child(&self, block_id: &BlockId) -> Result; + + /// Get a stream of import block notifications. + fn import_notification_stream(&self) -> sc_client_api::ImportNotifications; + + /// Wait for a block with a given hash in the relay chain. + /// + /// This method returns immediately on error or if the block is already + /// reported to be in chain. Otherwise, it waits for the block to arrive. + async fn wait_for_block(&self, hash: PHash) -> Result<(), WaitError>; + + /// Get a stream of finality notifications. + fn finality_notification_stream(&self) -> sc_client_api::FinalityNotifications; + + /// Get a stream of storage change notifications. + fn storage_changes_notification_stream( + &self, + filter_keys: Option<&[sc_client_api::StorageKey]>, + child_filter_keys: Option< + &[(sc_client_api::StorageKey, Option>)], + >, + ) -> sc_client_api::blockchain::Result>; + + /// Whether the synchronization service is undergoing major sync. + /// Returns true if so. + fn is_major_syncing(&self) -> bool; + + /// Get a handle to the overseer. + fn overseer_handle(&self) -> Option; + + /// Generate a storage read proof. + fn prove_read( + &self, + block_id: &BlockId, + relevant_keys: &Vec>, + ) -> Result, Box>; +} + +#[async_trait] +impl RelayChainInterface for Arc +where + T: RelayChainInterface + ?Sized, +{ + fn retrieve_dmq_contents( + &self, + para_id: ParaId, + relay_parent: PHash, + ) -> Option> { + (**self).retrieve_dmq_contents(para_id, relay_parent) + } + + fn retrieve_all_inbound_hrmp_channel_contents( + &self, + para_id: ParaId, + relay_parent: PHash, + ) -> Option>> { + (**self).retrieve_all_inbound_hrmp_channel_contents(para_id, relay_parent) + } + + fn persisted_validation_data( + &self, + block_id: &BlockId, + para_id: ParaId, + occupied_core_assumption: OccupiedCoreAssumption, + ) -> Result, ApiError> { + (**self).persisted_validation_data(block_id, para_id, occupied_core_assumption) + } + + fn candidate_pending_availability( + &self, + block_id: &BlockId, + para_id: ParaId, + ) -> Result, ApiError> { + (**self).candidate_pending_availability(block_id, para_id) + } + + fn session_index_for_child(&self, block_id: &BlockId) -> Result { + (**self).session_index_for_child(block_id) + } + + fn validators(&self, block_id: &BlockId) -> Result, ApiError> { + (**self).validators(block_id) + } + + fn import_notification_stream(&self) -> sc_client_api::ImportNotifications { + (**self).import_notification_stream() + } + + fn finality_notification_stream(&self) -> sc_client_api::FinalityNotifications { + (**self).finality_notification_stream() + } + + fn storage_changes_notification_stream( + &self, + filter_keys: Option<&[sc_client_api::StorageKey]>, + child_filter_keys: Option< + &[(sc_client_api::StorageKey, Option>)], + >, + ) -> sc_client_api::blockchain::Result> { + (**self).storage_changes_notification_stream(filter_keys, child_filter_keys) + } + + fn best_block_hash(&self) -> PHash { + (**self).best_block_hash() + } + + fn block_status(&self, block_id: BlockId) -> Result { + (**self).block_status(block_id) + } + + fn is_major_syncing(&self) -> bool { + (**self).is_major_syncing() + } + + fn overseer_handle(&self) -> Option { + (**self).overseer_handle() + } + + fn get_storage_by_key( + &self, + block_id: &BlockId, + key: &[u8], + ) -> Result, sp_blockchain::Error> { + (**self).get_storage_by_key(block_id, key) + } + + fn prove_read( + &self, + block_id: &BlockId, + relevant_keys: &Vec>, + ) -> Result, Box> { + (**self).prove_read(block_id, relevant_keys) + } + + async fn wait_for_block(&self, hash: PHash) -> Result<(), WaitError> { + (**self).wait_for_block(hash).await + } +} diff --git a/client/relay-chain-local/Cargo.toml b/client/relay-chain-local/Cargo.toml new file mode 100644 index 0000000000..a5150afeab --- /dev/null +++ b/client/relay-chain-local/Cargo.toml @@ -0,0 +1,43 @@ +[package] +authors = ["Parity Technologies "] +name = "cumulus-relay-chain-local" +version = "0.1.0" +edition = "2021" + +[dependencies] +polkadot-client = { git = "https://github.com/paritytech/polkadot", branch = "master" } +polkadot-service = { git = "https://github.com/paritytech/polkadot", branch = "master" } + +cumulus-primitives-core = { path = "../../primitives/core" } +cumulus-relay-chain-interface = { path = "../relay-chain-interface" } + +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-consensus = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-state-machine = { git = "https://github.com/paritytech/substrate", branch = "master" } + +sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-consensus-babe = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-network = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-service = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-telemetry = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-tracing = { git = "https://github.com/paritytech/substrate", branch = "master" } + +parking_lot = "0.11.1" +tracing = "0.1.25" +async-trait = "0.1.52" +futures = { version = "0.3.1", features = ["compat"] } +futures-timer = "3.0.2" + +[dev-dependencies] +# Cumulus deps +cumulus-test-service = { path = "../../test/service" } + +# Polkadot deps +polkadot-test-client = { git = "https://github.com/paritytech/polkadot", branch = "master" } +polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "master" } + +# substrate deps +sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/client/relay-chain-local/src/lib.rs b/client/relay-chain-local/src/lib.rs new file mode 100644 index 0000000000..5177d1f4af --- /dev/null +++ b/client/relay-chain-local/src/lib.rs @@ -0,0 +1,540 @@ +// Copyright 2021 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 std::{sync::Arc, time::Duration}; + +use async_trait::async_trait; +use cumulus_primitives_core::{ + relay_chain::{ + v1::{CommittedCandidateReceipt, OccupiedCoreAssumption, SessionIndex, ValidatorId}, + v2::ParachainHost, + Block as PBlock, BlockId, Hash as PHash, InboundHrmpMessage, + }, + InboundDownwardMessage, ParaId, PersistedValidationData, +}; +use cumulus_relay_chain_interface::{RelayChainInterface, WaitError}; +use futures::{FutureExt, StreamExt}; +use parking_lot::Mutex; +use polkadot_client::{ClientHandle, ExecuteWithClient, FullBackend}; +use polkadot_service::{ + AuxStore, BabeApi, CollatorPair, Configuration, Handle, NewFull, Role, TaskManager, +}; +use sc_client_api::{ + blockchain::BlockStatus, Backend, BlockchainEvents, HeaderBackend, ImportNotifications, + StorageProof, UsageProvider, +}; +use sc_telemetry::TelemetryWorkerHandle; +use sp_api::{ApiError, ProvideRuntimeApi}; +use sp_consensus::SyncOracle; +use sp_core::{sp_std::collections::btree_map::BTreeMap, Pair}; +use sp_state_machine::{Backend as StateBackend, StorageValue}; + +const LOG_TARGET: &str = "relay-chain-local"; +/// The timeout in seconds after that the waiting for a block should be aborted. +const TIMEOUT_IN_SECONDS: u64 = 6; + +/// Provides an implementation of the [`RelayChainInterface`] using a local in-process relay chain node. +pub struct RelayChainLocal { + full_client: Arc, + backend: Arc, + sync_oracle: Arc>>, + overseer_handle: Option, +} + +impl RelayChainLocal { + /// Create a new instance of [`RelayChainLocal`] + pub fn new( + full_client: Arc, + backend: Arc, + sync_oracle: Arc>>, + overseer_handle: Option, + ) -> Self { + Self { full_client, backend, sync_oracle, overseer_handle } + } +} + +impl Clone for RelayChainLocal { + fn clone(&self) -> Self { + Self { + full_client: self.full_client.clone(), + backend: self.backend.clone(), + sync_oracle: self.sync_oracle.clone(), + overseer_handle: self.overseer_handle.clone(), + } + } +} + +#[async_trait] +impl RelayChainInterface for RelayChainLocal +where + Client: ProvideRuntimeApi + + BlockchainEvents + + AuxStore + + UsageProvider + + Sync + + Send, + Client::Api: ParachainHost + BabeApi, +{ + fn retrieve_dmq_contents( + &self, + para_id: ParaId, + relay_parent: PHash, + ) -> Option> { + self.full_client + .runtime_api() + .dmq_contents_with_context( + &BlockId::hash(relay_parent), + sp_core::ExecutionContext::Importing, + para_id, + ) + .map_err(|e| { + tracing::error!( + target: LOG_TARGET, + relay_parent = ?relay_parent, + error = ?e, + "An error occured during requesting the downward messages.", + ); + }) + .ok() + } + + fn retrieve_all_inbound_hrmp_channel_contents( + &self, + para_id: ParaId, + relay_parent: PHash, + ) -> Option>> { + self.full_client + .runtime_api() + .inbound_hrmp_channels_contents_with_context( + &BlockId::hash(relay_parent), + sp_core::ExecutionContext::Importing, + para_id, + ) + .map_err(|e| { + tracing::error!( + target: LOG_TARGET, + relay_parent = ?relay_parent, + error = ?e, + "An error occured during requesting the inbound HRMP messages.", + ); + }) + .ok() + } + + fn persisted_validation_data( + &self, + block_id: &BlockId, + para_id: ParaId, + occupied_core_assumption: OccupiedCoreAssumption, + ) -> Result, ApiError> { + self.full_client.runtime_api().persisted_validation_data( + block_id, + para_id, + occupied_core_assumption, + ) + } + + fn candidate_pending_availability( + &self, + block_id: &BlockId, + para_id: ParaId, + ) -> Result, ApiError> { + self.full_client.runtime_api().candidate_pending_availability(block_id, para_id) + } + + fn session_index_for_child(&self, block_id: &BlockId) -> Result { + self.full_client.runtime_api().session_index_for_child(block_id) + } + + fn validators(&self, block_id: &BlockId) -> Result, ApiError> { + self.full_client.runtime_api().validators(block_id) + } + + fn import_notification_stream(&self) -> sc_client_api::ImportNotifications { + self.full_client.import_notification_stream() + } + + fn finality_notification_stream(&self) -> sc_client_api::FinalityNotifications { + self.full_client.finality_notification_stream() + } + + fn storage_changes_notification_stream( + &self, + filter_keys: Option<&[sc_client_api::StorageKey]>, + child_filter_keys: Option< + &[(sc_client_api::StorageKey, Option>)], + >, + ) -> sc_client_api::blockchain::Result> { + self.full_client + .storage_changes_notification_stream(filter_keys, child_filter_keys) + } + + fn best_block_hash(&self) -> PHash { + self.backend.blockchain().info().best_hash + } + + fn block_status(&self, block_id: BlockId) -> Result { + self.backend.blockchain().status(block_id) + } + + fn is_major_syncing(&self) -> bool { + let mut network = self.sync_oracle.lock(); + network.is_major_syncing() + } + + fn overseer_handle(&self) -> Option { + self.overseer_handle.clone() + } + + fn get_storage_by_key( + &self, + block_id: &BlockId, + key: &[u8], + ) -> Result, sp_blockchain::Error> { + let state = self.backend.state_at(*block_id)?; + state.storage(key).map_err(sp_blockchain::Error::Storage) + } + + fn prove_read( + &self, + block_id: &BlockId, + relevant_keys: &Vec>, + ) -> Result, Box> { + let state_backend = self + .backend + .state_at(*block_id) + .map_err(|e| { + tracing::error!( + target: LOG_TARGET, + relay_parent = ?block_id, + error = ?e, + "Cannot obtain the state of the relay chain.", + ); + }) + .ok(); + + match state_backend { + Some(state) => sp_state_machine::prove_read(state, relevant_keys) + .map_err(|e| { + tracing::error!( + target: LOG_TARGET, + relay_parent = ?block_id, + error = ?e, + "Failed to collect required relay chain state storage proof.", + ); + e + }) + .map(Some), + None => Ok(None), + } + } + + /// Wait for a given relay chain block in an async way. + /// + /// The caller needs to pass the hash of a block it waits for and the function will return when the + /// block is available or an error occurred. + /// + /// The waiting for the block is implemented as follows: + /// + /// 1. Get a read lock on the import lock from the backend. + /// + /// 2. Check if the block is already imported. If yes, return from the function. + /// + /// 3. If the block isn't imported yet, add an import notification listener. + /// + /// 4. Poll the import notification listener until the block is imported or the timeout is fired. + /// + /// The timeout is set to 6 seconds. This should be enough time to import the block in the current + /// round and if not, the new round of the relay chain already started anyway. + async fn wait_for_block(&self, hash: PHash) -> Result<(), WaitError> { + let mut listener = + match check_block_in_chain(self.backend.clone(), self.full_client.clone(), hash)? { + BlockCheckStatus::InChain => return Ok(()), + BlockCheckStatus::Unknown(listener) => listener, + }; + + let mut timeout = futures_timer::Delay::new(Duration::from_secs(TIMEOUT_IN_SECONDS)).fuse(); + + loop { + futures::select! { + _ = timeout => return Err(WaitError::Timeout(hash)), + evt = listener.next() => match evt { + Some(evt) if evt.hash == hash => return Ok(()), + // Not the event we waited on. + Some(_) => continue, + None => return Err(WaitError::ImportListenerClosed(hash)), + } + } + } + } +} + +pub enum BlockCheckStatus { + /// Block is in chain + InChain, + /// Block status is unknown, listener can be used to wait for notification + Unknown(ImportNotifications), +} + +// Helper function to check if a block is in chain. +pub fn check_block_in_chain( + backend: Arc, + client: Arc, + hash: PHash, +) -> Result +where + Client: BlockchainEvents, +{ + let _lock = backend.get_import_lock().read(); + + let block_id = BlockId::Hash(hash); + match backend.blockchain().status(block_id) { + Ok(BlockStatus::InChain) => return Ok(BlockCheckStatus::InChain), + Err(err) => return Err(WaitError::BlockchainError(hash, err)), + _ => {}, + } + + let listener = client.import_notification_stream(); + + Ok(BlockCheckStatus::Unknown(listener)) +} + +/// Builder for a concrete relay chain interface, created from a full node. Builds +/// a [`RelayChainLocal`] to access relay chain data necessary for parachain operation. +/// +/// The builder takes a [`polkadot_client::Client`] +/// that wraps a concrete instance. By using [`polkadot_client::ExecuteWithClient`] +/// the builder gets access to this concrete instance and instantiates a [`RelayChainLocal`] with it. +struct RelayChainLocalBuilder { + polkadot_client: polkadot_client::Client, + backend: Arc, + sync_oracle: Arc>>, + overseer_handle: Option, +} + +impl RelayChainLocalBuilder { + pub fn build(self) -> Arc { + self.polkadot_client.clone().execute_with(self) + } +} + +impl ExecuteWithClient for RelayChainLocalBuilder { + type Output = Arc; + + fn execute_with_client(self, client: Arc) -> Self::Output + where + Client: ProvideRuntimeApi + + BlockchainEvents + + AuxStore + + UsageProvider + + 'static + + Sync + + Send, + Client::Api: ParachainHost + BabeApi, + { + Arc::new(RelayChainLocal::new(client, self.backend, self.sync_oracle, self.overseer_handle)) + } +} + +/// Build the Polkadot full node using the given `config`. +#[sc_tracing::logging::prefix_logs_with("Relaychain")] +fn build_polkadot_full_node( + config: Configuration, + telemetry_worker_handle: Option, +) -> Result<(NewFull, CollatorPair), polkadot_service::Error> { + let is_light = matches!(config.role, Role::Light); + if is_light { + Err(polkadot_service::Error::Sub("Light client not supported.".into())) + } else { + let collator_key = CollatorPair::generate().0; + + let relay_chain_full_node = polkadot_service::build_full( + config, + polkadot_service::IsCollator::Yes(collator_key.clone()), + None, + true, + None, + telemetry_worker_handle, + polkadot_service::RealOverseerGen, + )?; + + Ok((relay_chain_full_node, collator_key)) + } +} + +/// Builds a relay chain interface by constructing a full relay chain node +pub fn build_relay_chain_interface( + polkadot_config: Configuration, + telemetry_worker_handle: Option, + task_manager: &mut TaskManager, +) -> Result<(Arc<(dyn RelayChainInterface + 'static)>, CollatorPair), polkadot_service::Error> { + let (full_node, collator_key) = + build_polkadot_full_node(polkadot_config, telemetry_worker_handle).map_err( + |e| match e { + polkadot_service::Error::Sub(x) => x, + s => format!("{}", s).into(), + }, + )?; + + let sync_oracle: Box = Box::new(full_node.network.clone()); + let sync_oracle = Arc::new(Mutex::new(sync_oracle)); + let relay_chain_interface_builder = RelayChainLocalBuilder { + polkadot_client: full_node.client.clone(), + backend: full_node.backend.clone(), + sync_oracle, + overseer_handle: full_node.overseer_handle.clone(), + }; + task_manager.add_child(full_node.task_manager); + + Ok((relay_chain_interface_builder.build(), collator_key)) +} + +#[cfg(test)] +mod tests { + use parking_lot::Mutex; + + use super::*; + + use polkadot_primitives::v1::Block as PBlock; + use polkadot_test_client::{ + construct_transfer_extrinsic, BlockBuilderExt, Client, ClientBlockImportExt, + DefaultTestClientBuilderExt, ExecutionStrategy, InitPolkadotBlockBuilder, + TestClientBuilder, TestClientBuilderExt, + }; + use sc_service::Arc; + use sp_consensus::{BlockOrigin, SyncOracle}; + use sp_runtime::traits::Block as BlockT; + + use futures::{executor::block_on, poll, task::Poll}; + + struct DummyNetwork {} + + impl SyncOracle for DummyNetwork { + fn is_major_syncing(&mut self) -> bool { + unimplemented!("Not needed for test") + } + + fn is_offline(&mut self) -> bool { + unimplemented!("Not needed for test") + } + } + + fn build_client_backend_and_block() -> (Arc, PBlock, RelayChainLocal) { + let builder = + TestClientBuilder::new().set_execution_strategy(ExecutionStrategy::NativeWhenPossible); + let backend = builder.backend(); + let client = Arc::new(builder.build()); + + let block_builder = client.init_polkadot_block_builder(); + let block = block_builder.build().expect("Finalizes the block").block; + let dummy_network: Box = Box::new(DummyNetwork {}); + + ( + client.clone(), + block, + RelayChainLocal::new( + client, + backend.clone(), + Arc::new(Mutex::new(dummy_network)), + None, + ), + ) + } + + #[test] + fn returns_directly_for_available_block() { + let (mut 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"); + + block_on(async move { + // Should be ready on the first poll + assert!(matches!( + poll!(relay_chain_interface.wait_for_block(hash)), + Poll::Ready(Ok(())) + )); + }); + } + + #[test] + fn resolve_after_block_import_notification_was_received() { + let (mut client, block, relay_chain_interface) = build_client_backend_and_block(); + let hash = block.hash(); + + block_on(async move { + let mut future = relay_chain_interface.wait_for_block(hash); + // As the block is not yet imported, the first poll should return `Pending` + assert!(poll!(&mut future).is_pending()); + + // Import the block that should fire the notification + client.import(BlockOrigin::Own, block).await.expect("Imports the block"); + + // Now it should have received the notification and report that the block was imported + assert!(matches!(poll!(future), Poll::Ready(Ok(())))); + }); + } + + #[test] + fn wait_for_block_time_out_when_block_is_not_imported() { + let (_, block, relay_chain_interface) = build_client_backend_and_block(); + let hash = block.hash(); + + assert!(matches!( + block_on(relay_chain_interface.wait_for_block(hash)), + Err(WaitError::Timeout(_)) + )); + } + + #[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 hash = block.hash(); + + let ext = construct_transfer_extrinsic( + &*client, + sp_keyring::Sr25519Keyring::Alice, + sp_keyring::Sr25519Keyring::Bob, + 1000, + ); + let mut block_builder = client.init_polkadot_block_builder(); + // Push an extrinsic to get a different block hash. + block_builder.push_polkadot_extrinsic(ext).expect("Push extrinsic"); + let block2 = block_builder.build().expect("Build second block").block; + let hash2 = block2.hash(); + + block_on(async move { + let mut future = relay_chain_interface.wait_for_block(hash); + let mut future2 = relay_chain_interface.wait_for_block(hash2); + // As the block is not yet imported, the first poll should return `Pending` + assert!(poll!(&mut future).is_pending()); + assert!(poll!(&mut future2).is_pending()); + + // Import the block that should fire the notification + client.import(BlockOrigin::Own, block2).await.expect("Imports the second block"); + + // The import notification of the second block should not make this one finish + assert!(poll!(&mut future).is_pending()); + // Now it should have received the notification and report that the block was imported + assert!(matches!(poll!(future2), Poll::Ready(Ok(())))); + + client.import(BlockOrigin::Own, block).await.expect("Imports the first block"); + + // Now it should be ready + assert!(matches!(poll!(future), Poll::Ready(Ok(())))); + }); + } +} diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index 051482ad34..ec2cd3ca86 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -2,13 +2,14 @@ name = "cumulus-client-service" version = "0.1.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" [dependencies] # Cumulus dependencies cumulus-client-consensus-common = { path = "../consensus/common" } cumulus-client-collator = { path = "../collator" } cumulus-client-pov-recovery = { path = "../pov-recovery" } +cumulus-relay-chain-interface = { path = "../relay-chain-interface" } cumulus-primitives-core = { path = "../../primitives/core" } # Substrate dependencies @@ -27,7 +28,6 @@ sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "mas # Polkadot dependencies polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "master" } -polkadot-service = { git = "https://github.com/paritytech/polkadot", branch = "master" } polkadot-overseer = { git = "https://github.com/paritytech/polkadot", branch = "master" } # Other deps diff --git a/client/service/src/genesis.rs b/client/service/src/genesis.rs index 12f3b4e3bd..b2d1686f51 100644 --- a/client/service/src/genesis.rs +++ b/client/service/src/genesis.rs @@ -21,21 +21,26 @@ use sp_runtime::traits::{Block as BlockT, Hash as HashT, Header as HeaderT, Zero /// Generate the genesis block from a given ChainSpec. pub fn generate_genesis_block( chain_spec: &Box, + genesis_state_version: sp_runtime::StateVersion, ) -> Result { let storage = chain_spec.build_storage()?; let child_roots = storage.children_default.iter().map(|(sk, child_content)| { let state_root = <<::Header as HeaderT>::Hashing as HashT>::trie_root( child_content.data.clone().into_iter().collect(), + genesis_state_version, ); (sk.clone(), state_root.encode()) }); let state_root = <<::Header as HeaderT>::Hashing as HashT>::trie_root( storage.top.clone().into_iter().chain(child_roots).collect(), + genesis_state_version, ); - let extrinsics_root = - <<::Header as HeaderT>::Hashing as HashT>::trie_root(Vec::new()); + let extrinsics_root = <<::Header as HeaderT>::Hashing as HashT>::trie_root( + Vec::new(), + sp_runtime::StateVersion::V0, + ); Ok(Block::new( <::Header as HeaderT>::new( diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index 10723ebc10..925c957c6f 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -20,9 +20,8 @@ use cumulus_client_consensus_common::ParachainConsensus; use cumulus_primitives_core::{CollectCollationInfo, ParaId}; -use polkadot_overseer::Handle as OverseerHandle; -use polkadot_primitives::v1::{Block as PBlock, CollatorPair}; -use polkadot_service::{AbstractClient, Client as PClient, ClientHandle, RuntimeApiCollection}; +use cumulus_relay_chain_interface::RelayChainInterface; +use polkadot_primitives::v1::CollatorPair; use sc_client_api::{ Backend as BackendT, BlockBackend, BlockchainEvents, Finalizer, UsageProvider, }; @@ -30,47 +29,32 @@ use sc_consensus::{ import_queue::{ImportQueue, IncomingBlock, Link, Origin}, BlockImport, }; -use sc_service::{Configuration, Role, TaskManager}; -use sc_telemetry::TelemetryWorkerHandle; +use sc_service::{Configuration, TaskManager}; use sp_api::ProvideRuntimeApi; use sp_blockchain::HeaderBackend; use sp_consensus::BlockOrigin; -use sp_core::{traits::SpawnNamed, Pair}; +use sp_core::traits::SpawnNamed; use sp_runtime::{ - traits::{BlakeTwo256, Block as BlockT, NumberFor}, + traits::{Block as BlockT, NumberFor}, Justifications, }; -use std::{marker::PhantomData, ops::Deref, sync::Arc}; +use std::{sync::Arc, time::Duration}; pub mod genesis; -/// The relay chain full node handle. -pub struct RFullNode { - /// The relay chain full node handles. - pub relay_chain_full_node: polkadot_service::NewFull, - /// The collator key used by the node. - pub collator_key: CollatorPair, -} - -impl Deref for RFullNode { - type Target = polkadot_service::NewFull; - - fn deref(&self) -> &Self::Target { - &self.relay_chain_full_node - } -} - /// Parameters given to [`start_collator`]. -pub struct StartCollatorParams<'a, Block: BlockT, BS, Client, Spawner, RClient, IQ> { +pub struct StartCollatorParams<'a, Block: BlockT, BS, Client, RCInterface, Spawner, IQ> { pub block_status: Arc, pub client: Arc, pub announce_block: Arc>) + Send + Sync>, pub spawner: Spawner, pub para_id: ParaId, - pub relay_chain_full_node: RFullNode, + pub relay_chain_interface: RCInterface, pub task_manager: &'a mut TaskManager, pub parachain_consensus: Box>, pub import_queue: IQ, + pub collator_key: CollatorPair, + pub slot_duration: Duration, } /// Start a collator node for a parachain. @@ -78,7 +62,7 @@ pub struct StartCollatorParams<'a, Block: BlockT, BS, Client, Spawner, RClient, /// A collator is similar to a validator in a normal blockchain. /// It is responsible for producing blocks and sending the blocks to a /// parachain validator for validation and inclusion into the relay chain. -pub async fn start_collator<'a, Block, BS, Client, Backend, Spawner, RClient, IQ>( +pub async fn start_collator<'a, Block, BS, Client, Backend, RCInterface, Spawner, IQ>( StartCollatorParams { block_status, client, @@ -86,10 +70,12 @@ pub async fn start_collator<'a, Block, BS, Client, Backend, Spawner, RClient, IQ spawner, para_id, task_manager, - relay_chain_full_node, + relay_chain_interface, parachain_consensus, import_queue, - }: StartCollatorParams<'a, Block, BS, Client, Spawner, RClient, IQ>, + collator_key, + slot_duration, + }: StartCollatorParams<'a, Block, BS, Client, RCInterface, Spawner, IQ>, ) -> sc_service::error::Result<()> where Block: BlockT, @@ -106,55 +92,58 @@ where Client::Api: CollectCollationInfo, for<'b> &'b Client: BlockImport, Spawner: SpawnNamed + Clone + Send + Sync + 'static, - RClient: ClientHandle, + RCInterface: RelayChainInterface + Clone + 'static, Backend: BackendT + 'static, IQ: ImportQueue + 'static, { - relay_chain_full_node.client.execute_with(StartConsensus { + let consensus = cumulus_client_consensus_common::run_parachain_consensus( para_id, - announce_block: announce_block.clone(), - client: client.clone(), - task_manager, - _phantom: PhantomData, - }); + client.clone(), + relay_chain_interface.clone(), + announce_block.clone(), + ); - relay_chain_full_node.client.execute_with(StartPoVRecovery { - para_id, - client: client.clone(), - import_queue, - task_manager, - overseer_handle: relay_chain_full_node - .overseer_handle - .clone() + task_manager + .spawn_essential_handle() + .spawn("cumulus-consensus", None, consensus); + + let pov_recovery = cumulus_client_pov_recovery::PoVRecovery::new( + relay_chain_interface + .overseer_handle() .ok_or_else(|| "Polkadot full node did not provide an `OverseerHandle`!")?, - _phantom: PhantomData, - })?; + slot_duration, + client.clone(), + import_queue, + relay_chain_interface.clone(), + para_id, + ); + + task_manager + .spawn_essential_handle() + .spawn("cumulus-pov-recovery", None, pov_recovery.run()); cumulus_client_collator::start_collator(cumulus_client_collator::StartCollatorParams { runtime_api: client.clone(), block_status, announce_block, - overseer_handle: relay_chain_full_node - .overseer_handle - .clone() + overseer_handle: relay_chain_interface + .overseer_handle() .ok_or_else(|| "Polkadot full node did not provide an `OverseerHandle`!")?, spawner, para_id, - key: relay_chain_full_node.collator_key.clone(), + key: collator_key, parachain_consensus, }) .await; - task_manager.add_child(relay_chain_full_node.relay_chain_full_node.task_manager); - Ok(()) } /// Parameters given to [`start_full_node`]. -pub struct StartFullNodeParams<'a, Block: BlockT, Client, PClient> { +pub struct StartFullNodeParams<'a, Block: BlockT, Client, RCInterface> { pub para_id: ParaId, pub client: Arc, - pub relay_chain_full_node: RFullNode, + pub relay_chain_interface: RCInterface, pub task_manager: &'a mut TaskManager, pub announce_block: Arc>) + Send + Sync>, } @@ -163,14 +152,14 @@ pub struct StartFullNodeParams<'a, Block: BlockT, Client, PClient> { /// /// A full node will only sync the given parachain and will follow the /// tip of the chain. -pub fn start_full_node( +pub fn start_full_node( StartFullNodeParams { client, announce_block, task_manager, - relay_chain_full_node, + relay_chain_interface, para_id, - }: StartFullNodeParams, + }: StartFullNodeParams, ) -> sc_service::error::Result<()> where Block: BlockT, @@ -183,112 +172,22 @@ where + 'static, for<'a> &'a Client: BlockImport, Backend: BackendT + 'static, - PClient: ClientHandle, + RCInterface: RelayChainInterface + Clone + 'static, { - relay_chain_full_node.client.execute_with(StartConsensus { - announce_block, + let consensus = cumulus_client_consensus_common::run_parachain_consensus( para_id, - client, - task_manager, - _phantom: PhantomData, - }); + client.clone(), + relay_chain_interface.clone(), + announce_block, + ); - task_manager.add_child(relay_chain_full_node.relay_chain_full_node.task_manager); + task_manager + .spawn_essential_handle() + .spawn("cumulus-consensus", None, consensus); Ok(()) } -struct StartConsensus<'a, Block: BlockT, Client, Backend> { - para_id: ParaId, - announce_block: Arc>) + Send + Sync>, - client: Arc, - task_manager: &'a mut TaskManager, - _phantom: PhantomData, -} - -impl<'a, Block, Client, Backend> polkadot_service::ExecuteWithClient - for StartConsensus<'a, Block, Client, Backend> -where - Block: BlockT, - Client: Finalizer - + UsageProvider - + Send - + Sync - + BlockBackend - + BlockchainEvents - + 'static, - for<'b> &'b Client: BlockImport, - Backend: BackendT + 'static, -{ - type Output = (); - - fn execute_with_client(self, client: Arc) -> Self::Output - where - >::StateBackend: sp_api::StateBackend, - PBackend: sc_client_api::Backend, - PBackend::State: sp_api::StateBackend, - Api: RuntimeApiCollection, - PClient: AbstractClient + 'static, - { - let consensus = cumulus_client_consensus_common::run_parachain_consensus( - self.para_id, - self.client.clone(), - client.clone(), - self.announce_block, - ); - - self.task_manager.spawn_essential_handle().spawn("cumulus-consensus", consensus); - } -} - -struct StartPoVRecovery<'a, Block: BlockT, Client, IQ> { - para_id: ParaId, - client: Arc, - task_manager: &'a mut TaskManager, - overseer_handle: OverseerHandle, - import_queue: IQ, - _phantom: PhantomData, -} - -impl<'a, Block, Client, IQ> polkadot_service::ExecuteWithClient - for StartPoVRecovery<'a, Block, Client, IQ> -where - Block: BlockT, - Client: UsageProvider - + Send - + Sync - + BlockBackend - + BlockchainEvents - + 'static, - IQ: ImportQueue + 'static, -{ - type Output = sc_service::error::Result<()>; - - fn execute_with_client(self, client: Arc) -> Self::Output - where - >::StateBackend: sp_api::StateBackend, - PBackend: sc_client_api::Backend, - PBackend::State: sp_api::StateBackend, - Api: RuntimeApiCollection, - PClient: AbstractClient + 'static, - { - let pov_recovery = cumulus_client_pov_recovery::PoVRecovery::new( - self.overseer_handle, - sc_consensus_babe::Config::get_or_compute(&*client)?.slot_duration(), - self.client, - self.import_queue, - client, - self.para_id, - ); - - self.task_manager - .spawn_essential_handle() - .spawn("cumulus-pov-recovery", pov_recovery.run()); - - Ok(()) - } -} - /// Prepare the parachain's node condifugration /// /// This function will disable the default announcement of Substrate for the parachain in favor @@ -299,32 +198,6 @@ pub fn prepare_node_config(mut parachain_config: Configuration) -> Configuration parachain_config } -/// Build the Polkadot full node using the given `config`. -#[sc_tracing::logging::prefix_logs_with("Relaychain")] -pub fn build_polkadot_full_node( - config: Configuration, - telemetry_worker_handle: Option, -) -> Result, polkadot_service::Error> { - let is_light = matches!(config.role, Role::Light); - if is_light { - Err(polkadot_service::Error::Sub("Light client not supported.".into())) - } else { - let collator_key = CollatorPair::generate().0; - - let relay_chain_full_node = polkadot_service::build_full( - config, - polkadot_service::IsCollator::Yes(collator_key.clone()), - None, - true, - None, - telemetry_worker_handle, - polkadot_service::RealOverseerGen, - )?; - - Ok(RFullNode { relay_chain_full_node, collator_key }) - } -} - /// A shared import queue /// /// This is basically a hack until the Substrate side is implemented properly. diff --git a/docker/injected.Dockerfile b/docker/injected.Dockerfile index d07fd7443f..f2d3ab6c45 100644 --- a/docker/injected.Dockerfile +++ b/docker/injected.Dockerfile @@ -36,6 +36,8 @@ RUN apt-get update && \ # add polkadot-collator binary to the docker image COPY ./target/release/polkadot-collator /usr/local/bin +COPY ./target/release/polkadot-collator.asc /usr/local/bin +COPY ./target/release/polkadot-collator.sha256 /usr/local/bin COPY ./polkadot-parachains/res/*.json /specs/ USER polkadot diff --git a/docker/polkadot-collator_builder.Containerfile b/docker/polkadot-collator_builder.Containerfile new file mode 100644 index 0000000000..4eb7ec04a1 --- /dev/null +++ b/docker/polkadot-collator_builder.Containerfile @@ -0,0 +1,36 @@ +# This file is sourced from https://github.com/paritytech/polkadot/blob/master/scripts/dockerfiles/polkadot/polkadot_builder.Dockerfile +# This is the build stage for Polkadot-collator. Here we create the binary in a temporary image. +FROM docker.io/paritytech/ci-linux:production as builder + +WORKDIR /cumulus +COPY . /cumulus + +RUN cargo build --release --locked -p polkadot-collator + +# This is the 2nd stage: a very small image where we copy the Polkadot binary." +FROM docker.io/library/ubuntu:20.04 + +LABEL io.parity.image.type="builder" \ + io.parity.image.authors="devops-team@parity.io" \ + io.parity.image.vendor="Parity Technologies" \ + io.parity.image.description="Multistage Docker image for Polkadot-collator" \ + io.parity.image.source="https://github.com/paritytech/polkadot/blob/${VCS_REF}/docker/test-parachain-collator.dockerfile" \ + io.parity.image.documentation="https://github.com/paritytech/cumulus" + +COPY --from=builder /cumulus/target/release/polkadot-collator /usr/local/bin + +RUN useradd -m -u 1000 -U -s /bin/sh -d /cumulus polkadot-collator && \ + mkdir -p /data /cumulus/.local/share && \ + chown -R polkadot-collator:polkadot-collator /data && \ + ln -s /data /cumulus/.local/share/polkadot-collator && \ +# unclutter and minimize the attack surface + rm -rf /usr/bin /usr/sbin && \ +# check if executable works in this container + /usr/local/bin/polkadot-collator --version + +USER polkadot-collator + +EXPOSE 30333 9933 9944 9615 +VOLUME ["/data"] + +ENTRYPOINT ["/usr/local/bin/polkadot-collator"] diff --git a/docker/scripts/build-injected-image.sh b/docker/scripts/build-injected-image.sh index c498cff2f9..6ba392d121 100755 --- a/docker/scripts/build-injected-image.sh +++ b/docker/scripts/build-injected-image.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -OWNER=parity -IMAGE_NAME=polkadot-collator +OWNER=${OWNER:-parity} +IMAGE_NAME=${IMAGE_NAME:-polkadot-collator} docker build --no-cache --build-arg IMAGE_NAME=$IMAGE_NAME -t $OWNER/$IMAGE_NAME -f ./docker/injected.Dockerfile . docker images | grep $IMAGE_NAME diff --git a/docker/test-parachain-collator.dockerfile b/docker/test-parachain-collator.dockerfile index 35fe09c68a..72e4e0d67e 100644 --- a/docker/test-parachain-collator.dockerfile +++ b/docker/test-parachain-collator.dockerfile @@ -1,23 +1,8 @@ -FROM rust:buster as builder +# This file is sourced from https://github.com/paritytech/polkadot/blob/master/scripts/dockerfiles/polkadot/polkadot_builder.Dockerfile +FROM docker.io/paritytech/ci-linux:production as builder -RUN apt-get update && apt-get install time clang libclang-dev llvm -y -RUN rustup toolchain install nightly -RUN rustup target add wasm32-unknown-unknown --toolchain nightly -RUN command -v wasm-gc || cargo +nightly install --git https://github.com/alexcrichton/wasm-gc --force - -WORKDIR /paritytech/cumulus - -# Ideally, we could just do something like `COPY . .`, but that doesn't work: -# it busts the cache every time non-source files like inject_bootnodes.sh change, -# as well as when non-`.dockerignore`'d transient files (*.log and friends) -# show up. There is no way to exclude particular files, or write a negative -# rule, using Docker's COPY syntax, which derives from go's filepath.Match rules. -# -# We can't combine these into a single big COPY operation like -# `COPY collator consensus network runtime test Cargo.* .`, because in that case -# docker will copy the _contents_ of each directory into the image workdir, -# not the actual directory. We're stuck just enumerating them. -COPY . . +WORKDIR /cumulus +COPY . /cumulus RUN cargo build --release --locked -p polkadot-collator diff --git a/pallets/asset-tx-payment/Cargo.toml b/pallets/asset-tx-payment/Cargo.toml deleted file mode 100644 index 5723776fd4..0000000000 --- a/pallets/asset-tx-payment/Cargo.toml +++ /dev/null @@ -1,52 +0,0 @@ -[package] -name = "pallet-asset-tx-payment" -version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2018" -license = "Apache-2.0" -homepage = "https://substrate.io" -repository = "https://github.com/paritytech/cumulus/" -description = "pallet to manage transaction payments in assets" -readme = "README.md" - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[dependencies] -# Substrate dependencies -frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } -frame-system = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } -pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } -sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } -sp-io = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } -sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } -sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } - -# Other dependencies -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.101", optional = true } - -[dev-dependencies] -smallvec = "1.4.1" -serde_json = "1.0.41" - -pallet-assets = { git = "https://github.com/paritytech/substrate", branch = "master" } -pallet-authorship = { git = "https://github.com/paritytech/substrate", branch = "master" } -pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master" } -sp-storage = { git = "https://github.com/paritytech/substrate", branch = "master" } - -[features] -default = ["std"] -std = [ - "serde", - "codec/std", - "sp-std/std", - "sp-runtime/std", - "frame-support/std", - "frame-system/std", - "sp-io/std", - "sp-core/std", - "pallet-transaction-payment/std", -] -try-runtime = ["frame-support/try-runtime"] diff --git a/pallets/asset-tx-payment/README.md b/pallets/asset-tx-payment/README.md deleted file mode 100644 index fc860347d8..0000000000 --- a/pallets/asset-tx-payment/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# pallet-asset-tx-payment - -## Asset Transaction Payment Pallet - -This pallet allows runtimes that include it to pay for transactions in assets other than the -native token of the chain. - -### Overview -It does this by extending transactions to include an optional `AssetId` that specifies the asset -to be used for payment (defaulting to the native token on `None`). It expects an -[`OnChargeAssetTransaction`] implementation analogously to [`pallet-transaction-payment`]. The -included [`FungiblesAdapter`] (implementing [`OnChargeAssetTransaction`]) determines the fee -amount by converting the fee calculated by [`pallet-transaction-payment`] into the desired -asset. - -### Integration -This pallet wraps FRAME's transaction payment pallet and functions as a replacement. This means -you should include both pallets in your `construct_runtime` macro, but only include this -pallet's [`SignedExtension`] ([`ChargeAssetTxPayment`]). - -License: Apache-2.0 diff --git a/pallets/asset-tx-payment/src/lib.rs b/pallets/asset-tx-payment/src/lib.rs deleted file mode 100644 index 6ca91cbf3e..0000000000 --- a/pallets/asset-tx-payment/src/lib.rs +++ /dev/null @@ -1,295 +0,0 @@ -// Copyright (C) 2021 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 Transaction Payment Pallet -//! -//! This pallet allows runtimes that include it to pay for transactions in assets other than the -//! main token of the chain. -//! -//! ## Overview -//! It does this by extending transactions to include an optional `AssetId` that specifies the asset -//! to be used for payment (defaulting to the native token on `None`). It expects an -//! [`OnChargeAssetTransaction`] implementation analogously to [`pallet-transaction-payment`]. The -//! included [`FungiblesAdapter`] (implementing [`OnChargeAssetTransaction`]) determines the fee -//! amount by converting the fee calculated by [`pallet-transaction-payment`] into the desired -//! asset. -//! -//! ## Integration -//! This pallet wraps FRAME's transaction payment pallet and functions as a replacement. This means -//! you should include both pallets in your `construct_runtime` macro, but only include this -//! pallet's [`SignedExtension`] ([`ChargeAssetTxPayment`]). - -#![cfg_attr(not(feature = "std"), no_std)] - -use sp_std::prelude::*; - -use codec::{Decode, Encode}; -use frame_support::{ - dispatch::DispatchResult, - traits::{ - tokens::{ - fungibles::{Balanced, CreditOf, Inspect}, - WithdrawConsequence, - }, - IsType, - }, - weights::{DispatchInfo, PostDispatchInfo}, - DefaultNoBound, -}; -use pallet_transaction_payment::OnChargeTransaction; -use scale_info::TypeInfo; -use sp_runtime::{ - traits::{DispatchInfoOf, Dispatchable, PostDispatchInfoOf, SignedExtension, Zero}, - transaction_validity::{ - InvalidTransaction, TransactionValidity, TransactionValidityError, ValidTransaction, - }, - FixedPointOperand, -}; - -#[cfg(test)] -mod tests; - -mod payment; -pub use payment::*; - -// Type aliases used for interaction with `OnChargeTransaction`. -pub(crate) type OnChargeTransactionOf = - ::OnChargeTransaction; -// Balance type alias. -pub(crate) type BalanceOf = as OnChargeTransaction>::Balance; -// Liquity info type alias. -pub(crate) type LiquidityInfoOf = - as OnChargeTransaction>::LiquidityInfo; - -// Type alias used for interaction with fungibles (assets). -// Balance type alias. -pub(crate) type AssetBalanceOf = - <::Fungibles as Inspect<::AccountId>>::Balance; -/// Asset id type alias. -pub(crate) type AssetIdOf = - <::Fungibles as Inspect<::AccountId>>::AssetId; - -// Type aliases used for interaction with `OnChargeAssetTransaction`. -// Balance type alias. -pub(crate) type ChargeAssetBalanceOf = - <::OnChargeAssetTransaction as OnChargeAssetTransaction>::Balance; -// Asset id type alias. -pub(crate) type ChargeAssetIdOf = - <::OnChargeAssetTransaction as OnChargeAssetTransaction>::AssetId; -// Liquity info type alias. -pub(crate) type ChargeAssetLiquidityOf = - <::OnChargeAssetTransaction as OnChargeAssetTransaction>::LiquidityInfo; - -/// Used to pass the initial payment info from pre- to post-dispatch. -#[derive(Encode, Decode, DefaultNoBound, TypeInfo)] -pub enum InitialPayment { - /// No initial fee was payed. - Nothing, - /// The initial fee was payed in the native currency. - Native(LiquidityInfoOf), - /// The initial fee was payed in an asset. - Asset(CreditOf), -} - -pub use pallet::*; - -#[frame_support::pallet] -pub mod pallet { - use super::*; - - use frame_support::pallet_prelude::*; - use frame_system::pallet_prelude::*; - - #[pallet::config] - pub trait Config: frame_system::Config + pallet_transaction_payment::Config { - /// The fungibles instance used to pay for transactions in assets. - type Fungibles: Balanced; - /// The actual transaction charging logic that charges the fees. - type OnChargeAssetTransaction: OnChargeAssetTransaction; - } - - #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] - pub struct Pallet(_); - - #[pallet::hooks] - impl Hooks> for Pallet {} - - #[pallet::call] - impl Pallet {} -} - -/// Require the transactor pay for themselves and maybe include a tip to gain additional priority -/// in the queue. Allows paying via both `Currency` as well as `fungibles::Balanced`. -/// -/// Wraps the transaction logic in [`pallet_transaction_payment`] and extends it with assets. -/// An asset id of `None` falls back to the underlying transaction payment via the native currency. -#[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo)] -#[scale_info(skip_type_params(T))] -pub struct ChargeAssetTxPayment { - #[codec(compact)] - tip: BalanceOf, - asset_id: Option>, -} - -impl ChargeAssetTxPayment -where - T::Call: Dispatchable, - AssetBalanceOf: Send + Sync + FixedPointOperand, - BalanceOf: Send + Sync + FixedPointOperand + IsType>, - ChargeAssetIdOf: Send + Sync, - CreditOf: IsType>, -{ - /// utility constructor. Used only in client/factory code. - pub fn from(tip: BalanceOf, asset_id: Option>) -> Self { - Self { tip, asset_id } - } - - /// Fee withdrawal logic that dispatches to either `OnChargeAssetTransaction` or `OnChargeTransaction`. - fn withdraw_fee( - &self, - who: &T::AccountId, - call: &T::Call, - info: &DispatchInfoOf, - len: usize, - ) -> Result<(BalanceOf, InitialPayment), TransactionValidityError> { - let fee = pallet_transaction_payment::Pallet::::compute_fee(len as u32, info, self.tip); - debug_assert!(self.tip <= fee, "tip should be included in the computed fee"); - if fee.is_zero() { - Ok((fee, InitialPayment::Nothing)) - } else if let Some(asset_id) = self.asset_id { - T::OnChargeAssetTransaction::withdraw_fee( - who, - call, - info, - asset_id, - fee.into(), - self.tip.into(), - ) - .map(|i| (fee, InitialPayment::Asset(i.into()))) - } else { - as OnChargeTransaction>::withdraw_fee( - who, call, info, fee, self.tip, - ) - .map(|i| (fee, InitialPayment::Native(i))) - .map_err(|_| -> TransactionValidityError { InvalidTransaction::Payment.into() }) - } - } -} - -impl sp_std::fmt::Debug for ChargeAssetTxPayment { - #[cfg(feature = "std")] - fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { - write!(f, "ChargeAssetTxPayment<{:?}, {:?}>", self.tip, self.asset_id.encode()) - } - #[cfg(not(feature = "std"))] - fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { - Ok(()) - } -} - -impl SignedExtension for ChargeAssetTxPayment -where - T::Call: Dispatchable, - AssetBalanceOf: Send + Sync + FixedPointOperand, - BalanceOf: Send + Sync + From + FixedPointOperand + IsType>, - ChargeAssetIdOf: Send + Sync, - CreditOf: IsType>, -{ - const IDENTIFIER: &'static str = "ChargeAssetTxPayment"; - type AccountId = T::AccountId; - type Call = T::Call; - type AdditionalSigned = (); - type Pre = ( - // tip - BalanceOf, - // who paid the fee - Self::AccountId, - // imbalance resulting from withdrawing the fee - InitialPayment, - ); - - fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> { - Ok(()) - } - - fn validate( - &self, - who: &Self::AccountId, - call: &Self::Call, - info: &DispatchInfoOf, - len: usize, - ) -> TransactionValidity { - use pallet_transaction_payment::ChargeTransactionPayment; - let (fee, _) = self.withdraw_fee(who, call, info, len)?; - let priority = ChargeTransactionPayment::::get_priority(info, len, self.tip, fee); - Ok(ValidTransaction { priority, ..Default::default() }) - } - - fn pre_dispatch( - self, - who: &Self::AccountId, - call: &Self::Call, - info: &DispatchInfoOf, - len: usize, - ) -> Result { - let (_fee, initial_payment) = self.withdraw_fee(who, call, info, len)?; - Ok((self.tip, who.clone(), initial_payment)) - } - - fn post_dispatch( - pre: Self::Pre, - info: &DispatchInfoOf, - post_info: &PostDispatchInfoOf, - len: usize, - _result: &DispatchResult, - ) -> Result<(), TransactionValidityError> { - let (tip, who, initial_payment) = pre; - let actual_fee = pallet_transaction_payment::Pallet::::compute_actual_fee( - len as u32, info, post_info, tip, - ); - match initial_payment { - InitialPayment::Native(already_withdrawn) => { - as OnChargeTransaction>::correct_and_deposit_fee( - &who, - info, - post_info, - actual_fee, - tip, - already_withdrawn, - )?; - }, - InitialPayment::Asset(already_withdrawn) => { - T::OnChargeAssetTransaction::correct_and_deposit_fee( - &who, - info, - post_info, - actual_fee.into(), - tip.into(), - already_withdrawn.into(), - )?; - }, - InitialPayment::Nothing => { - debug_assert!( - actual_fee.is_zero(), - "actual fee should be zero if initial fee was zero." - ); - debug_assert!(tip.is_zero(), "tip should be zero if initial fee was zero."); - }, - } - - Ok(()) - } -} diff --git a/pallets/asset-tx-payment/src/payment.rs b/pallets/asset-tx-payment/src/payment.rs deleted file mode 100644 index 09482f9649..0000000000 --- a/pallets/asset-tx-payment/src/payment.rs +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright (C) 2021 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. - -///! Traits and default implementation for paying transaction fees in assets. -use super::*; -use crate::Config; - -use codec::FullCodec; -use frame_support::{ - traits::{ - fungibles::{Balanced, CreditOf, Inspect}, - tokens::BalanceConversion, - }, - unsigned::TransactionValidityError, -}; -use scale_info::TypeInfo; -use sp_runtime::{ - traits::{ - AtLeast32BitUnsigned, DispatchInfoOf, MaybeSerializeDeserialize, One, PostDispatchInfoOf, - }, - transaction_validity::InvalidTransaction, -}; -use sp_std::{fmt::Debug, marker::PhantomData}; - -/// Handle withdrawing, refunding and depositing of transaction fees. -pub trait OnChargeAssetTransaction { - /// The underlying integer type in which fees are calculated. - type Balance: AtLeast32BitUnsigned - + FullCodec - + Copy - + MaybeSerializeDeserialize - + Debug - + Default - + TypeInfo; - /// The type used to identify the assets used for transaction payment. - type AssetId: FullCodec + Copy + MaybeSerializeDeserialize + Debug + Default + Eq + TypeInfo; - /// The type used to store the intermediate values between pre- and post-dispatch. - type LiquidityInfo; - - /// Before the transaction is executed the payment of the transaction fees needs to be secured. - /// - /// Note: The `fee` already includes the `tip`. - fn withdraw_fee( - who: &T::AccountId, - call: &T::Call, - dispatch_info: &DispatchInfoOf, - asset_id: Self::AssetId, - fee: Self::Balance, - tip: Self::Balance, - ) -> Result; - - /// After the transaction was executed the actual fee can be calculated. - /// This function should refund any overpaid fees and optionally deposit - /// the corrected amount. - /// - /// Note: The `fee` already includes the `tip`. - fn correct_and_deposit_fee( - who: &T::AccountId, - dispatch_info: &DispatchInfoOf, - post_info: &PostDispatchInfoOf, - corrected_fee: Self::Balance, - tip: Self::Balance, - already_withdrawn: Self::LiquidityInfo, - ) -> Result<(), TransactionValidityError>; -} - -/// Allows specifying what to do with the withdrawn asset fees. -pub trait HandleCredit> { - /// Implement to determine what to do with the withdrawn asset fees. - /// Default for `CreditOf` from the assets pallet is to burn and - /// decrease total issuance. - fn handle_credit(credit: CreditOf); -} - -/// Default implementation that just drops the credit according to the `OnDrop` in the underlying -/// imbalance type. -impl> HandleCredit for () { - fn handle_credit(_credit: CreditOf) {} -} - -/// Implements the asset transaction for a balance to asset converter (implementing -/// [`BalanceConversion`]) and a credit handler (implementing [`HandleCredit`]). -/// -/// The credit handler is given the complete fee in terms of the asset used for the transaction. -pub struct FungiblesAdapter(PhantomData<(CON, HC)>); - -/// Default implementation for a runtime instantiating this pallet, a balance to asset converter and -/// a credit handler. -impl OnChargeAssetTransaction for FungiblesAdapter -where - T: Config, - CON: BalanceConversion, AssetIdOf, AssetBalanceOf>, - HC: HandleCredit, - AssetIdOf: FullCodec + Copy + MaybeSerializeDeserialize + Debug + Default + Eq + TypeInfo, -{ - type Balance = BalanceOf; - type AssetId = AssetIdOf; - type LiquidityInfo = CreditOf; - - /// Withdraw the predicted fee from the transaction origin. - /// - /// Note: The `fee` already includes the `tip`. - fn withdraw_fee( - who: &T::AccountId, - _call: &T::Call, - _info: &DispatchInfoOf, - asset_id: Self::AssetId, - fee: Self::Balance, - _tip: Self::Balance, - ) -> Result { - // We don't know the precision of the underlying asset. Because the converted fee could be - // less than one (e.g. 0.5) but gets rounded down by integer division we introduce a minimum - // fee. - let min_converted_fee = if fee.is_zero() { Zero::zero() } else { One::one() }; - let converted_fee = CON::to_asset_balance(fee, asset_id) - .map_err(|_| TransactionValidityError::from(InvalidTransaction::Payment))? - .max(min_converted_fee); - let can_withdraw = >::can_withdraw( - asset_id.into(), - who, - converted_fee, - ); - if !matches!(can_withdraw, WithdrawConsequence::Success) { - return Err(InvalidTransaction::Payment.into()) - } - >::withdraw(asset_id.into(), who, converted_fee) - .map_err(|_| TransactionValidityError::from(InvalidTransaction::Payment)) - } - - /// Hand the fee and the tip over to the `[HandleCredit]` implementation. - /// Since the predicted fee might have been too high, parts of the fee may be refunded. - /// - /// Note: The `corrected_fee` already includes the `tip`. - fn correct_and_deposit_fee( - who: &T::AccountId, - _dispatch_info: &DispatchInfoOf, - _post_info: &PostDispatchInfoOf, - corrected_fee: Self::Balance, - _tip: Self::Balance, - paid: Self::LiquidityInfo, - ) -> Result<(), TransactionValidityError> { - let min_converted_fee = if corrected_fee.is_zero() { Zero::zero() } else { One::one() }; - // Convert the corrected fee into the asset used for payment. - let converted_fee = CON::to_asset_balance(corrected_fee, paid.asset().into()) - .map_err(|_| -> TransactionValidityError { InvalidTransaction::Payment.into() })? - .max(min_converted_fee); - // Calculate how much refund we should return. - let (final_fee, refund) = paid.split(converted_fee); - // Refund to the account that paid the fees. If this fails, the account might have dropped - // below the existential balance. In that case we don't refund anything. - let _ = >::resolve(who, refund); - // Handle the final fee, e.g. by transferring to the block author or burning. - HC::handle_credit(final_fee); - Ok(()) - } -} diff --git a/pallets/asset-tx-payment/src/tests.rs b/pallets/asset-tx-payment/src/tests.rs deleted file mode 100644 index 97330c5a49..0000000000 --- a/pallets/asset-tx-payment/src/tests.rs +++ /dev/null @@ -1,636 +0,0 @@ -// Copyright (C) 2021 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 crate as pallet_asset_tx_payment; - -use frame_support::{ - assert_ok, - pallet_prelude::*, - parameter_types, - traits::{fungibles::Mutate, FindAuthor}, - weights::{ - DispatchClass, DispatchInfo, PostDispatchInfo, Weight, WeightToFeeCoefficient, - WeightToFeeCoefficients, WeightToFeePolynomial, - }, - ConsensusEngineId, -}; -use frame_system as system; -use frame_system::EnsureRoot; -use pallet_balances::Call as BalancesCall; -use pallet_transaction_payment::CurrencyAdapter; -use smallvec::smallvec; -use sp_core::H256; -use sp_runtime::{ - testing::Header, - traits::{BlakeTwo256, ConvertInto, IdentityLookup, StaticLookup}, - Perbill, -}; -use std::cell::RefCell; - -type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; -type Block = frame_system::mocking::MockBlock; -type Balance = u64; -type AccountId = u64; - -frame_support::construct_runtime!( - pub enum Runtime where - Block = Block, - NodeBlock = Block, - UncheckedExtrinsic = UncheckedExtrinsic, - { - System: system::{Pallet, Call, Config, Storage, Event}, - Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - TransactionPayment: pallet_transaction_payment::{Pallet, Storage}, - Assets: pallet_assets::{Pallet, Call, Storage, Event}, - Authorship: pallet_authorship::{Pallet, Call, Storage}, - AssetTxPayment: pallet_asset_tx_payment::{Pallet}, - } -); - -const CALL: &::Call = - &Call::Balances(BalancesCall::transfer { dest: 2, value: 69 }); - -thread_local! { - static EXTRINSIC_BASE_WEIGHT: RefCell = RefCell::new(0); -} - -pub struct BlockWeights; -impl Get for BlockWeights { - fn get() -> frame_system::limits::BlockWeights { - frame_system::limits::BlockWeights::builder() - .base_block(0) - .for_class(DispatchClass::all(), |weights| { - weights.base_extrinsic = EXTRINSIC_BASE_WEIGHT.with(|v| *v.borrow()).into(); - }) - .for_class(DispatchClass::non_mandatory(), |weights| { - weights.max_total = 1024.into(); - }) - .build_or_panic() - } -} - -parameter_types! { - pub const BlockHashCount: u64 = 250; - pub static TransactionByteFee: u64 = 1; - pub static WeightToFee: u64 = 1; -} - -impl frame_system::Config for Runtime { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = BlockWeights; - type BlockLength = (); - type DbWeight = (); - type Origin = Origin; - type Index = u64; - type BlockNumber = u64; - type Call = Call; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = AccountId; - type Lookup = IdentityLookup; - type Header = Header; - type Event = Event; - type BlockHashCount = BlockHashCount; - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); -} - -parameter_types! { - pub const ExistentialDeposit: u64 = 10; - pub const MaxReserves: u32 = 50; -} - -impl pallet_balances::Config for Runtime { - type Balance = Balance; - type Event = Event; - type DustRemoval = (); - type ExistentialDeposit = ExistentialDeposit; - type AccountStore = System; - type MaxLocks = (); - type WeightInfo = (); - type MaxReserves = MaxReserves; - type ReserveIdentifier = [u8; 8]; -} - -impl WeightToFeePolynomial for WeightToFee { - type Balance = u64; - - fn polynomial() -> WeightToFeeCoefficients { - smallvec![WeightToFeeCoefficient { - degree: 1, - coeff_frac: Perbill::zero(), - coeff_integer: WEIGHT_TO_FEE.with(|v| *v.borrow()), - negative: false, - }] - } -} - -parameter_types! { - pub const OperationalFeeMultiplier: u8 = 5; -} - -impl pallet_transaction_payment::Config for Runtime { - type OnChargeTransaction = CurrencyAdapter; - type TransactionByteFee = TransactionByteFee; - type WeightToFee = WeightToFee; - type FeeMultiplierUpdate = (); - type OperationalFeeMultiplier = OperationalFeeMultiplier; -} - -parameter_types! { - pub const AssetDeposit: u64 = 2; - pub const MetadataDeposit: u64 = 0; - pub const StringLimit: u32 = 20; -} - -impl pallet_assets::Config for Runtime { - type Event = Event; - type Balance = Balance; - type AssetId = u32; - type Currency = Balances; - type ForceOrigin = EnsureRoot; - type AssetDeposit = AssetDeposit; - type MetadataDepositBase = MetadataDeposit; - type MetadataDepositPerByte = MetadataDeposit; - type ApprovalDeposit = MetadataDeposit; - type StringLimit = StringLimit; - type Freezer = (); - type Extra = (); - type WeightInfo = (); -} - -pub struct HardcodedAuthor; -const BLOCK_AUTHOR: AccountId = 1234; -impl FindAuthor for HardcodedAuthor { - fn find_author<'a, I>(_: I) -> Option - where - I: 'a + IntoIterator, - { - Some(BLOCK_AUTHOR) - } -} - -impl pallet_authorship::Config for Runtime { - type FindAuthor = HardcodedAuthor; - type UncleGenerations = (); - type FilterUncle = (); - type EventHandler = (); -} - -pub struct CreditToBlockAuthor; -impl HandleCredit for CreditToBlockAuthor { - fn handle_credit(credit: CreditOf) { - let author = pallet_authorship::Pallet::::author(); - // TODO: what to do in case paying the author fails (e.g. because `fee < min_balance`) - // default: drop the result which will trigger the `OnDrop` of the imbalance. - let _ = >::resolve(&author, credit); - } -} - -impl Config for Runtime { - type Fungibles = Assets; - type OnChargeAssetTransaction = FungiblesAdapter< - pallet_assets::BalanceToAssetBalance, - CreditToBlockAuthor, - >; -} - -pub struct ExtBuilder { - balance_factor: u64, - base_weight: u64, - byte_fee: u64, - weight_to_fee: u64, -} - -impl Default for ExtBuilder { - fn default() -> Self { - Self { balance_factor: 1, base_weight: 0, byte_fee: 1, weight_to_fee: 1 } - } -} - -impl ExtBuilder { - pub fn base_weight(mut self, base_weight: u64) -> Self { - self.base_weight = base_weight; - self - } - pub fn balance_factor(mut self, factor: u64) -> Self { - self.balance_factor = factor; - self - } - fn set_constants(&self) { - EXTRINSIC_BASE_WEIGHT.with(|v| *v.borrow_mut() = self.base_weight); - TRANSACTION_BYTE_FEE.with(|v| *v.borrow_mut() = self.byte_fee); - WEIGHT_TO_FEE.with(|v| *v.borrow_mut() = self.weight_to_fee); - } - pub fn build(self) -> sp_io::TestExternalities { - self.set_constants(); - let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); - pallet_balances::GenesisConfig:: { - balances: if self.balance_factor > 0 { - vec![ - (1, 10 * self.balance_factor), - (2, 20 * self.balance_factor), - (3, 30 * self.balance_factor), - (4, 40 * self.balance_factor), - (5, 50 * self.balance_factor), - (6, 60 * self.balance_factor), - ] - } else { - vec![] - }, - } - .assimilate_storage(&mut t) - .unwrap(); - t.into() - } -} - -/// create a transaction info struct from weight. Handy to avoid building the whole struct. -pub fn info_from_weight(w: Weight) -> DispatchInfo { - // pays_fee: Pays::Yes -- class: DispatchClass::Normal - DispatchInfo { weight: w, ..Default::default() } -} - -fn post_info_from_weight(w: Weight) -> PostDispatchInfo { - PostDispatchInfo { actual_weight: Some(w), pays_fee: Default::default() } -} - -fn info_from_pays(p: Pays) -> DispatchInfo { - DispatchInfo { pays_fee: p, ..Default::default() } -} - -fn post_info_from_pays(p: Pays) -> PostDispatchInfo { - PostDispatchInfo { actual_weight: None, pays_fee: p } -} - -fn default_post_info() -> PostDispatchInfo { - PostDispatchInfo { actual_weight: None, pays_fee: Default::default() } -} - -#[test] -fn transaction_payment_in_native_possible() { - let balance_factor = 100; - ExtBuilder::default() - .balance_factor(balance_factor) - .base_weight(5) - .build() - .execute_with(|| { - let len = 10; - let pre = ChargeAssetTxPayment::::from(0, None) - .pre_dispatch(&1, CALL, &info_from_weight(5), len) - .unwrap(); - let initial_balance = 10 * balance_factor; - assert_eq!(Balances::free_balance(1), initial_balance - 5 - 5 - 10); - - assert_ok!(ChargeAssetTxPayment::::post_dispatch( - pre, - &info_from_weight(5), - &default_post_info(), - len, - &Ok(()) - )); - assert_eq!(Balances::free_balance(1), initial_balance - 5 - 5 - 10); - - let pre = ChargeAssetTxPayment::::from(5 /* tipped */, None) - .pre_dispatch(&2, CALL, &info_from_weight(100), len) - .unwrap(); - let initial_balance_for_2 = 20 * balance_factor; - assert_eq!(Balances::free_balance(2), initial_balance_for_2 - 5 - 10 - 100 - 5); - - assert_ok!(ChargeAssetTxPayment::::post_dispatch( - pre, - &info_from_weight(100), - &post_info_from_weight(50), - len, - &Ok(()) - )); - assert_eq!(Balances::free_balance(2), initial_balance_for_2 - 5 - 10 - 50 - 5); - }); -} - -#[test] -fn transaction_payment_in_asset_possible() { - let base_weight = 5; - let balance_factor = 100; - ExtBuilder::default() - .balance_factor(balance_factor) - .base_weight(base_weight) - .build() - .execute_with(|| { - // create the asset - let asset_id = 1; - let min_balance = 2; - assert_ok!(Assets::force_create( - Origin::root(), - asset_id, - 42, /* owner */ - true, /* is_sufficient */ - min_balance - )); - - // mint into the caller account - let caller = 1; - let beneficiary = ::Lookup::unlookup(caller); - let balance = 100; - assert_ok!(Assets::mint_into(asset_id, &beneficiary, balance)); - assert_eq!(Assets::balance(asset_id, caller), balance); - let weight = 5; - let len = 10; - // we convert the from weight to fee based on the ratio between asset min balance and - // existential deposit - let fee = (base_weight + weight + len as u64) * min_balance / ExistentialDeposit::get(); - let pre = ChargeAssetTxPayment::::from(0, Some(asset_id)) - .pre_dispatch(&caller, CALL, &info_from_weight(weight), len) - .unwrap(); - // assert that native balance is not used - assert_eq!(Balances::free_balance(caller), 10 * balance_factor); - // check that fee was charged in the given asset - assert_eq!(Assets::balance(asset_id, caller), balance - fee); - assert_eq!(Assets::balance(asset_id, BLOCK_AUTHOR), 0); - - assert_ok!(ChargeAssetTxPayment::::post_dispatch( - pre, - &info_from_weight(weight), - &default_post_info(), - len, - &Ok(()) - )); - assert_eq!(Assets::balance(asset_id, caller), balance - fee); - // check that the block author gets rewarded - assert_eq!(Assets::balance(asset_id, BLOCK_AUTHOR), fee); - }); -} - -#[test] -fn transaction_payment_without_fee() { - let base_weight = 5; - let balance_factor = 100; - ExtBuilder::default() - .balance_factor(balance_factor) - .base_weight(base_weight) - .build() - .execute_with(|| { - // create the asset - let asset_id = 1; - let min_balance = 2; - assert_ok!(Assets::force_create( - Origin::root(), - asset_id, - 42, /* owner */ - true, /* is_sufficient */ - min_balance - )); - - // mint into the caller account - let caller = 1; - let beneficiary = ::Lookup::unlookup(caller); - let balance = 100; - assert_ok!(Assets::mint_into(asset_id, &beneficiary, balance)); - assert_eq!(Assets::balance(asset_id, caller), balance); - let weight = 5; - let len = 10; - // we convert the from weight to fee based on the ratio between asset min balance and - // existential deposit - let fee = (base_weight + weight + len as u64) * min_balance / ExistentialDeposit::get(); - let pre = ChargeAssetTxPayment::::from(0, Some(asset_id)) - .pre_dispatch(&caller, CALL, &info_from_weight(weight), len) - .unwrap(); - // assert that native balance is not used - assert_eq!(Balances::free_balance(caller), 10 * balance_factor); - // check that fee was charged in the given asset - assert_eq!(Assets::balance(asset_id, caller), balance - fee); - assert_eq!(Assets::balance(asset_id, BLOCK_AUTHOR), 0); - - assert_ok!(ChargeAssetTxPayment::::post_dispatch( - pre, - &info_from_weight(weight), - &post_info_from_pays(Pays::No), - len, - &Ok(()) - )); - // caller should be refunded - assert_eq!(Assets::balance(asset_id, caller), balance); - // check that the block author did not get rewarded - assert_eq!(Assets::balance(asset_id, BLOCK_AUTHOR), 0); - }); -} - -#[test] -fn asset_transaction_payment_with_tip_and_refund() { - let base_weight = 5; - ExtBuilder::default() - .balance_factor(100) - .base_weight(base_weight) - .build() - .execute_with(|| { - // create the asset - let asset_id = 1; - let min_balance = 2; - assert_ok!(Assets::force_create( - Origin::root(), - asset_id, - 42, /* owner */ - true, /* is_sufficient */ - min_balance - )); - - // mint into the caller account - let caller = 2; - let beneficiary = ::Lookup::unlookup(caller); - let balance = 1000; - assert_ok!(Assets::mint_into(asset_id, &beneficiary, balance)); - assert_eq!(Assets::balance(asset_id, caller), balance); - let weight = 100; - let tip = 5; - let len = 10; - // we convert the from weight to fee based on the ratio between asset min balance and - // existential deposit - let fee_with_tip = - (base_weight + weight + len as u64 + tip) * min_balance / ExistentialDeposit::get(); - let pre = ChargeAssetTxPayment::::from(tip, Some(asset_id)) - .pre_dispatch(&caller, CALL, &info_from_weight(weight), len) - .unwrap(); - assert_eq!(Assets::balance(asset_id, caller), balance - fee_with_tip); - - let final_weight = 50; - assert_ok!(ChargeAssetTxPayment::::post_dispatch( - pre, - &info_from_weight(weight), - &post_info_from_weight(final_weight), - len, - &Ok(()) - )); - let final_fee = - fee_with_tip - (weight - final_weight) * min_balance / ExistentialDeposit::get(); - assert_eq!(Assets::balance(asset_id, caller), balance - (final_fee)); - assert_eq!(Assets::balance(asset_id, BLOCK_AUTHOR), final_fee); - }); -} - -#[test] -fn payment_from_account_with_only_assets() { - let base_weight = 5; - ExtBuilder::default() - .balance_factor(100) - .base_weight(base_weight) - .build() - .execute_with(|| { - // create the asset - let asset_id = 1; - let min_balance = 2; - assert_ok!(Assets::force_create( - Origin::root(), - asset_id, - 42, /* owner */ - true, /* is_sufficient */ - min_balance - )); - - // mint into the caller account - let caller = 333; - let beneficiary = ::Lookup::unlookup(caller); - let balance = 100; - assert_ok!(Assets::mint_into(asset_id, &beneficiary, balance)); - assert_eq!(Assets::balance(asset_id, caller), balance); - // assert that native balance is not necessary - assert_eq!(Balances::free_balance(caller), 0); - let weight = 5; - let len = 10; - // we convert the from weight to fee based on the ratio between asset min balance and - // existential deposit - let fee = (base_weight + weight + len as u64) * min_balance / ExistentialDeposit::get(); - let pre = ChargeAssetTxPayment::::from(0, Some(asset_id)) - .pre_dispatch(&caller, CALL, &info_from_weight(weight), len) - .unwrap(); - assert_eq!(Balances::free_balance(caller), 0); - // check that fee was charged in the given asset - assert_eq!(Assets::balance(asset_id, caller), balance - fee); - - assert_ok!(ChargeAssetTxPayment::::post_dispatch( - pre, - &info_from_weight(weight), - &default_post_info(), - len, - &Ok(()) - )); - assert_eq!(Assets::balance(asset_id, caller), balance - fee); - assert_eq!(Balances::free_balance(caller), 0); - }); -} - -#[test] -fn payment_only_with_existing_sufficient_asset() { - let base_weight = 5; - ExtBuilder::default() - .balance_factor(100) - .base_weight(base_weight) - .build() - .execute_with(|| { - let asset_id = 1; - let caller = 1; - let weight = 5; - let len = 10; - // pre_dispatch fails for non-existent asset - assert!(ChargeAssetTxPayment::::from(0, Some(asset_id)) - .pre_dispatch(&caller, CALL, &info_from_weight(weight), len) - .is_err()); - - // create the non-sufficient asset - let min_balance = 2; - assert_ok!(Assets::force_create( - Origin::root(), - asset_id, - 42, /* owner */ - false, /* is_sufficient */ - min_balance - )); - // pre_dispatch fails for non-sufficient asset - assert!(ChargeAssetTxPayment::::from(0, Some(asset_id)) - .pre_dispatch(&caller, CALL, &info_from_weight(weight), len) - .is_err()); - }); -} - -#[test] -fn converted_fee_is_never_zero_if_input_fee_is_not() { - let base_weight = 1; - ExtBuilder::default() - .balance_factor(100) - .base_weight(base_weight) - .build() - .execute_with(|| { - // create the asset - let asset_id = 1; - let min_balance = 1; - assert_ok!(Assets::force_create( - Origin::root(), - asset_id, - 42, /* owner */ - true, /* is_sufficient */ - min_balance - )); - - // mint into the caller account - let caller = 333; - let beneficiary = ::Lookup::unlookup(caller); - let balance = 100; - assert_ok!(Assets::mint_into(asset_id, &beneficiary, balance)); - assert_eq!(Assets::balance(asset_id, caller), balance); - let weight = 1; - let len = 1; - // we convert the from weight to fee based on the ratio between asset min balance and - // existential deposit - let fee = (base_weight + weight + len as u64) * min_balance / ExistentialDeposit::get(); - // naive fee calculation would round down to zero - assert_eq!(fee, 0); - { - let pre = ChargeAssetTxPayment::::from(0, Some(asset_id)) - .pre_dispatch(&caller, CALL, &info_from_pays(Pays::No), len) - .unwrap(); - // `Pays::No` still implies no fees - assert_eq!(Assets::balance(asset_id, caller), balance); - - assert_ok!(ChargeAssetTxPayment::::post_dispatch( - pre, - &info_from_pays(Pays::No), - &post_info_from_pays(Pays::No), - len, - &Ok(()) - )); - assert_eq!(Assets::balance(asset_id, caller), balance); - } - let pre = ChargeAssetTxPayment::::from(0, Some(asset_id)) - .pre_dispatch(&caller, CALL, &info_from_weight(weight), len) - .unwrap(); - // check that at least one coin was charged in the given asset - assert_eq!(Assets::balance(asset_id, caller), balance - 1); - - assert_ok!(ChargeAssetTxPayment::::post_dispatch( - pre, - &info_from_weight(weight), - &default_post_info(), - len, - &Ok(()) - )); - assert_eq!(Assets::balance(asset_id, caller), balance - 1); - }); -} diff --git a/pallets/aura-ext/Cargo.toml b/pallets/aura-ext/Cargo.toml index 72b3366dab..c6cb38248c 100644 --- a/pallets/aura-ext/Cargo.toml +++ b/pallets/aura-ext/Cargo.toml @@ -2,7 +2,7 @@ name = "cumulus-pallet-aura-ext" version = "0.1.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" description = "AURA consensus extension pallet for parachains" [dependencies] @@ -19,7 +19,7 @@ sp-application-crypto = { git = "https://github.com/paritytech/substrate", defau # Other Dependencies codec = { package = "parity-scale-codec", version = "2.3.0", default-features = false, features = ["derive"]} scale-info = { version = "1.0.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.101", optional = true, features = ["derive"] } +serde = { version = "1.0.132", optional = true, features = ["derive"] } [dev-dependencies] cumulus-pallet-parachain-system = { path = "../parachain-system" } diff --git a/pallets/collator-selection/Cargo.toml b/pallets/collator-selection/Cargo.toml index d486ee85df..c36a52ea2b 100644 --- a/pallets/collator-selection/Cargo.toml +++ b/pallets/collator-selection/Cargo.toml @@ -1,62 +1,64 @@ [package] -authors = ['Anonymous'] -description = 'Simple staking pallet with a fixed stake.' -edition = '2018' -homepage = 'https://substrate.io' -license = 'Apache-2.0' -name = 'pallet-collator-selection' -readme = 'README.md' -repository = 'https://github.com/paritytech/cumulus/' -version = '3.0.0' +authors = ["Anonymous"] +description = "Simple staking pallet with a fixed stake." +edition = "2021" +homepage = "https://substrate.io" +license = "Apache-2.0" +name = "pallet-collator-selection" +readme = "README.md" +repository = "https://github.com/paritytech/cumulus/" +version = "3.0.0" [package.metadata.docs.rs] -targets = ['x86_64-unknown-linux-gnu'] +targets = ["x86_64-unknown-linux-gnu"] [dependencies] log = { version = "0.4.0", default-features = false } -codec = { default-features = false, features = ['derive'], package = 'parity-scale-codec', version = '2.3.0' } +codec = { default-features = false, features = ["derive"], package = "parity-scale-codec", version = "2.3.0" } rand = { version = "0.7.2", default-features = false } scale-info = { version = "1.0.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.119", default-features = false } +serde = { version = "1.0.132", default-features = false } -sp-std = { default-features = false, git = 'https://github.com/paritytech/substrate', branch = "master" } -sp-runtime = { default-features = false, git = 'https://github.com/paritytech/substrate', branch = "master" } -sp-staking = { default-features = false, git = 'https://github.com/paritytech/substrate', branch = "master" } -frame-support = { default-features = false, git = 'https://github.com/paritytech/substrate', branch = "master" } -frame-system = { default-features = false, git = 'https://github.com/paritytech/substrate', branch = "master" } -pallet-authorship = { default-features = false, git = 'https://github.com/paritytech/substrate', branch = "master" } -pallet-session = { default-features = false, git = 'https://github.com/paritytech/substrate', branch = "master" } +sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" } +sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" } +sp-staking = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" } +frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" } +frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" } +pallet-authorship = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" } +pallet-session = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" } -frame-benchmarking = { default-features = false, optional = true, git = 'https://github.com/paritytech/substrate', branch = "master" } +frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "master" } [dev-dependencies] -sp-core = { git = 'https://github.com/paritytech/substrate', branch = "master" } -sp-io = { git = 'https://github.com/paritytech/substrate', branch = "master" } -sp-tracing = { git = 'https://github.com/paritytech/substrate', branch = "master" } -sp-runtime = { git = 'https://github.com/paritytech/substrate', branch = "master" } -pallet-timestamp = { git = 'https://github.com/paritytech/substrate', branch = "master" } -sp-consensus-aura = { git = 'https://github.com/paritytech/substrate', branch = "master" } -pallet-balances = { git = 'https://github.com/paritytech/substrate', branch = "master" } -pallet-aura = { git = 'https://github.com/paritytech/substrate', branch = "master" } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-io = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-tracing = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } +pallet-timestamp = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-consensus-aura = { git = "https://github.com/paritytech/substrate", branch = "master" } +pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master" } +pallet-aura = { git = "https://github.com/paritytech/substrate", branch = "master" } [features] -default = ['std'] +default = ["std"] runtime-benchmarks = [ - 'frame-benchmarking', - 'frame-support/runtime-benchmarks', - 'frame-system/runtime-benchmarks', + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", ] std = [ - 'codec/std', - 'log/std', - 'scale-info/std', - 'rand/std', - 'sp-runtime/std', - 'sp-staking/std', - 'sp-std/std', - 'frame-support/std', - 'frame-system/std', - 'frame-benchmarking/std', - 'pallet-authorship/std', - 'pallet-session/std', + "codec/std", + "log/std", + "scale-info/std", + "rand/std", + "sp-runtime/std", + "sp-staking/std", + "sp-std/std", + "frame-support/std", + "frame-system/std", + "frame-benchmarking/std", + "pallet-authorship/std", + "pallet-session/std", ] + +try-runtime = [ "frame-support/try-runtime" ] diff --git a/pallets/collator-selection/src/benchmarking.rs b/pallets/collator-selection/src/benchmarking.rs index d66ff50a13..cc91fd88ec 100644 --- a/pallets/collator-selection/src/benchmarking.rs +++ b/pallets/collator-selection/src/benchmarking.rs @@ -88,7 +88,7 @@ fn register_validators(count: u32) { let validators = (0..count).map(|c| validator::(c)).collect::>(); for (who, keys) in validators { - >::set_keys(RawOrigin::Signed(who).into(), keys, vec![]).unwrap(); + >::set_keys(RawOrigin::Signed(who).into(), keys, Vec::new()).unwrap(); } } @@ -157,10 +157,10 @@ benchmarks! { let bond: BalanceOf = T::Currency::minimum_balance() * 2u32.into(); T::Currency::make_free_balance_be(&caller, bond.clone()); - >::set_keys( + >::set_keys( RawOrigin::Signed(caller.clone()).into(), keys::(c + 1), - vec![] + Vec::new() ).unwrap(); }: _(RawOrigin::Signed(caller.clone())) diff --git a/pallets/collator-selection/src/mock.rs b/pallets/collator-selection/src/mock.rs index 600d4bc12c..a3aa8a20cc 100644 --- a/pallets/collator-selection/src/mock.rs +++ b/pallets/collator-selection/src/mock.rs @@ -78,6 +78,7 @@ impl system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = SS58Prefix; type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { @@ -145,7 +146,7 @@ impl From for MockSessionKeys { } parameter_types! { - pub static SessionHandlerCollators: Vec = vec![]; + pub static SessionHandlerCollators: Vec = Vec::new(); pub static SessionChangeBlock: u64 = 0; } @@ -224,21 +225,21 @@ pub fn new_test_ext() -> sp_io::TestExternalities { sp_tracing::try_init_simple(); let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); let invulnerables = vec![1, 2]; - let keys = invulnerables - .iter() - .map(|i| (*i, *i, MockSessionKeys { aura: UintAuthorityId(*i) })) - .collect::>(); - let balances = pallet_balances::GenesisConfig:: { - balances: vec![(1, 100), (2, 100), (3, 100), (4, 100), (5, 100)], - }; + let balances = vec![(1, 100), (2, 100), (3, 100), (4, 100), (5, 100)]; + let keys = balances + .iter() + .map(|&(i, _)| (i, i, MockSessionKeys { aura: UintAuthorityId(i) })) + .collect::>(); let collator_selection = collator_selection::GenesisConfig:: { desired_candidates: 2, candidacy_bond: 10, invulnerables, }; let session = pallet_session::GenesisConfig:: { keys }; - balances.assimilate_storage(&mut t).unwrap(); + pallet_balances::GenesisConfig:: { balances } + .assimilate_storage(&mut t) + .unwrap(); // collator selection must be initialized before session. collator_selection.assimilate_storage(&mut t).unwrap(); session.assimilate_storage(&mut t).unwrap(); @@ -249,6 +250,6 @@ pub fn new_test_ext() -> sp_io::TestExternalities { pub fn initialize_to_block(n: u64) { for i in System::block_number() + 1..=n { System::set_block_number(i); - >::on_initialize(i); + >::on_initialize(i); } } diff --git a/pallets/collator-selection/src/tests.rs b/pallets/collator-selection/src/tests.rs index 7ccfc308ea..d8cba9f227 100644 --- a/pallets/collator-selection/src/tests.rs +++ b/pallets/collator-selection/src/tests.rs @@ -188,7 +188,7 @@ fn register_as_candidate_works() { // given assert_eq!(CollatorSelection::desired_candidates(), 2); assert_eq!(CollatorSelection::candidacy_bond(), 10); - assert_eq!(CollatorSelection::candidates(), vec![]); + assert_eq!(CollatorSelection::candidates(), Vec::new()); assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]); // take two endowed, non-invulnerables accounts. diff --git a/pallets/dmp-queue/Cargo.toml b/pallets/dmp-queue/Cargo.toml index 402fc658f5..13075e5504 100644 --- a/pallets/dmp-queue/Cargo.toml +++ b/pallets/dmp-queue/Cargo.toml @@ -2,7 +2,7 @@ name = "cumulus-pallet-dmp-queue" version = "0.1.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" [dependencies] # Other dependencies diff --git a/pallets/dmp-queue/src/lib.rs b/pallets/dmp-queue/src/lib.rs index 8766f618d6..d3c08a1763 100644 --- a/pallets/dmp-queue/src/lib.rs +++ b/pallets/dmp-queue/src/lib.rs @@ -307,7 +307,7 @@ pub mod pallet { id, remaining, required, )); } - } + }, } } // Cannot be an `else` here since the `maybe_enqueue_page` may have changed. @@ -371,6 +371,7 @@ mod tests { impl_version: 1, apis: sp_version::create_apis_vec!([]), transaction_version: 1, + state_version: 1, }; pub const ParachainId: ParaId = ParaId::new(200); pub const ReservedXcmpWeight: Weight = 0; @@ -403,6 +404,7 @@ mod tests { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } thread_local! { @@ -475,7 +477,7 @@ mod tests { Xcm(vec![Transact { origin_kind: OriginKind::Native, require_weight_at_most: weight, - call: vec![].into(), + call: Vec::new().into(), }]) } @@ -506,7 +508,7 @@ mod tests { new_test_ext().execute_with(|| { let weight_used = handle_messages(&[], 1000); assert_eq!(weight_used, 0); - assert_eq!(take_trace(), vec![]); + assert_eq!(take_trace(), Vec::new()); assert!(queue_is_empty()); }); } diff --git a/pallets/parachain-system/Cargo.toml b/pallets/parachain-system/Cargo.toml index feee0b090a..25a8980dd6 100644 --- a/pallets/parachain-system/Cargo.toml +++ b/pallets/parachain-system/Cargo.toml @@ -2,7 +2,7 @@ name = "cumulus-pallet-parachain-system" version = "0.1.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" description = "Base pallet for cumulus-based parachains" [dependencies] @@ -32,7 +32,7 @@ sp-externalities = { git = "https://github.com/paritytech/substrate", default-fe # Other Dependencies codec = { package = "parity-scale-codec", version = "2.3.0", default-features = false, features = ["derive"]} scale-info = { version = "1.0.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.101", optional = true, features = ["derive"] } +serde = { version = "1.0.132", optional = true, features = ["derive"] } log = { version = "0.4.14", default-features = false } environmental = { version = "1.1.2", default-features = false } diff --git a/pallets/parachain-system/proc-macro/Cargo.toml b/pallets/parachain-system/proc-macro/Cargo.toml index ea47cfdfc4..7231cb62f5 100644 --- a/pallets/parachain-system/proc-macro/Cargo.toml +++ b/pallets/parachain-system/proc-macro/Cargo.toml @@ -2,15 +2,15 @@ name = "cumulus-pallet-parachain-system-proc-macro" version = "0.1.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" description = "Proc macros provided by the parachain-system pallet" [lib] proc-macro = true [dependencies] -syn = "1.0.73" -proc-macro2 = "1.0.27" +syn = "1.0.81" +proc-macro2 = "1.0.36" quote = "1.0.9" proc-macro-crate = "1.0.0" diff --git a/pallets/parachain-system/src/lib.rs b/pallets/parachain-system/src/lib.rs index 198a7646f3..620befc3dc 100644 --- a/pallets/parachain-system/src/lib.rs +++ b/pallets/parachain-system/src/lib.rs @@ -33,7 +33,7 @@ use cumulus_primitives_core::{ OutboundHrmpMessage, ParaId, PersistedValidationData, UpwardMessage, UpwardMessageSender, XcmpMessageHandler, XcmpMessageSource, }; -use cumulus_primitives_parachain_inherent::ParachainInherentData; +use cumulus_primitives_parachain_inherent::{MessageQueueChain, ParachainInherentData}; use frame_support::{ dispatch::{DispatchError, DispatchResult}, ensure, @@ -46,7 +46,7 @@ use frame_system::{ensure_none, ensure_root}; use polkadot_parachain::primitives::RelayChainBlockNumber; use relay_state_snapshot::MessagingStateSnapshot; use sp_runtime::{ - traits::{BlakeTwo256, Block as BlockT, BlockNumberProvider, Hash}, + traits::{Block as BlockT, BlockNumberProvider, Hash}, transaction_validity::{ InvalidTransaction, TransactionLongevity, TransactionSource, TransactionValidity, ValidTransaction, @@ -236,8 +236,9 @@ pub mod pallet { HrmpWatermark::::kill(); UpwardMessages::::kill(); HrmpOutboundMessages::::kill(); + CustomValidationHeadData::::kill(); - weight += T::DbWeight::get().writes(5); + weight += T::DbWeight::get().writes(6); // Here, in `on_initialize` we must report the weight for both `on_initialize` and // `on_finalize`. @@ -567,6 +568,12 @@ pub mod pallet { #[pallet::storage] pub(super) type AuthorizedUpgrade = StorageValue<_, T::Hash>; + /// A custom head data that should be returned as result of `validate_block`. + /// + /// See [`Pallet::set_custom_validation_head_data`] for more information. + #[pallet::storage] + pub(super) type CustomValidationHeadData = StorageValue<_, Vec, OptionQuery>; + #[pallet::inherent] impl ProvideInherent for Pallet { type Call = Call; @@ -609,7 +616,7 @@ pub mod pallet { if let Ok(hash) = Self::validate_authorized_upgrade(code) { return Ok(ValidTransaction { priority: 100, - requires: vec![], + requires: Vec::new(), provides: vec![hash.as_ref().to_vec()], longevity: TransactionLongevity::max_value(), propagate: true, @@ -692,6 +699,9 @@ impl Pallet { /// import, this is a no-op. /// /// # Panics + /// + /// Panics while validating the `PoV` on the relay chain if the [`PersistedValidationData`] + /// passed by the block author was incorrect. fn validate_validation_data(validation_data: &PersistedValidationData) { validate_block::with_validation_params(|params| { assert_eq!( @@ -714,8 +724,10 @@ impl Pallet { /// Checks if the sequence of the messages is valid, dispatches them and communicates the /// number of processed messages to the collator via a storage update. /// - /// **Panics** if it turns out that after processing all messages the Message Queue Chain - /// hash doesn't match the expected. + /// # Panics + /// + /// If it turns out that after processing all messages the Message Queue Chain + /// hash doesn't match the expected. fn process_inbound_downward_messages( expected_dmq_mqc_head: relay_chain::Hash, downward_messages: Vec, @@ -738,7 +750,7 @@ impl Pallet { weight_used += T::DmpMessageHandler::handle_dmp_messages(message_iter, max_weight); >::put(&dmq_head); - Self::deposit_event(Event::DownwardMessagesProcessed(weight_used, dmq_head.0)); + Self::deposit_event(Event::DownwardMessagesProcessed(weight_used, dmq_head.head())); } // After hashing each message in the message queue chain submitted by the collator, we @@ -746,7 +758,7 @@ impl Pallet { // // A mismatch means that at least some of the submitted messages were altered, omitted or // added improperly. - assert_eq!(dmq_head.0, expected_dmq_mqc_head); + assert_eq!(dmq_head.head(), expected_dmq_mqc_head); ProcessedDownwardMessages::::put(dm_count); @@ -907,6 +919,22 @@ impl Pallet { new_validation_code: NewValidationCode::::get().map(Into::into), } } + + /// 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 + /// validating a `PoV` on the relay chain. Normally the head data that is being returned + /// by `validate_block` is the header of the block that is validated, thus it can be + /// enacted as the new best block. However, for features like forking it can be useful + /// to overwrite the head data with a custom header. + /// + /// # Attention + /// + /// This should only be used when you are sure what you are doing as this can brick + /// your Parachain. + pub fn set_custom_validation_head_data(head_data: Vec) { + CustomValidationHeadData::::put(head_data); + } } pub struct ParachainSetCode(sp_std::marker::PhantomData); @@ -917,43 +945,6 @@ impl frame_system::SetCode for ParachainSetCode { } } -/// This struct provides ability to extend a message queue chain (MQC) and compute a new head. -/// -/// MQC is an instance of a [hash chain] applied to a message queue. Using a hash chain it's -/// possible to represent a sequence of messages using only a single hash. -/// -/// A head for an empty chain is agreed to be a zero hash. -/// -/// [hash chain]: https://en.wikipedia.org/wiki/Hash_chain -#[derive(Default, Clone, codec::Encode, codec::Decode, scale_info::TypeInfo)] -struct MessageQueueChain(relay_chain::Hash); - -impl MessageQueueChain { - fn extend_hrmp(&mut self, horizontal_message: &InboundHrmpMessage) -> &mut Self { - let prev_head = self.0; - self.0 = BlakeTwo256::hash_of(&( - prev_head, - horizontal_message.sent_at, - BlakeTwo256::hash_of(&horizontal_message.data), - )); - self - } - - fn extend_downward(&mut self, downward_message: &InboundDownwardMessage) -> &mut Self { - let prev_head = self.0; - self.0 = BlakeTwo256::hash_of(&( - prev_head, - downward_message.sent_at, - BlakeTwo256::hash_of(&downward_message.msg), - )); - self - } - - fn head(&self) -> relay_chain::Hash { - self.0 - } -} - impl Pallet { pub fn send_upward_message(message: UpwardMessage) -> Result { // Check if the message fits into the relay-chain constraints. @@ -1008,7 +999,7 @@ pub trait CheckInherents { ) -> frame_support::inherent::CheckInherentsResult; } -/// Implements [`BlockNumberProvider`] that returns relaychain block number fetched from +/// Implements [`BlockNumberProvider`] that returns relay chain block number fetched from /// validation data. /// NTOE: When validation data is not available (e.g. within on_initialize), 0 will be returned. pub struct RelaychainBlockNumberProvider(sp_std::marker::PhantomData); diff --git a/pallets/parachain-system/src/tests.rs b/pallets/parachain-system/src/tests.rs index eed1b1e86d..3b8444878b 100755 --- a/pallets/parachain-system/src/tests.rs +++ b/pallets/parachain-system/src/tests.rs @@ -33,7 +33,10 @@ use frame_system::{InitKind, RawOrigin}; use hex_literal::hex; use relay_chain::v1::HrmpChannelId; use sp_core::H256; -use sp_runtime::{testing::Header, traits::IdentityLookup}; +use sp_runtime::{ + testing::Header, + traits::{BlakeTwo256, IdentityLookup}, +}; use sp_version::RuntimeVersion; use std::cell::RefCell; @@ -63,6 +66,7 @@ parameter_types! { impl_version: 1, apis: sp_version::create_apis_vec!([]), transaction_version: 1, + state_version: 1, }; pub const ParachainId: ParaId = ParaId::new(200); pub const ReservedXcmpWeight: Weight = 0; @@ -92,6 +96,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = ParachainSetCode; + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl Config for Test { type Event = Event; diff --git a/pallets/parachain-system/src/validate_block/implementation.rs b/pallets/parachain-system/src/validate_block/implementation.rs index 63a1016c42..4aac6d8778 100644 --- a/pallets/parachain-system/src/validate_block/implementation.rs +++ b/pallets/parachain-system/src/validate_block/implementation.rs @@ -17,7 +17,7 @@ //! The actual implementation of the validate block functionality. use frame_support::traits::{ExecuteBlock, ExtrinsicCall, Get, IsSubType}; -use sp_runtime::traits::{Block as BlockT, Extrinsic, HashFor, Header as HeaderT, NumberFor}; +use sp_runtime::traits::{Block as BlockT, Extrinsic, HashFor, Header as HeaderT}; use sp_io::KillStorageResult; use sp_std::prelude::*; @@ -26,13 +26,13 @@ use polkadot_parachain::primitives::{HeadData, ValidationParams, ValidationResul use codec::{Decode, Encode}; -use sp_core::storage::ChildInfo; +use sp_core::storage::{ChildInfo, StateVersion}; use sp_externalities::{set_and_run_with_externalities, Externalities}; use sp_trie::MemoryDB; type TrieBackend = sp_state_machine::TrieBackend>, HashFor>; -type Ext<'a, B> = sp_state_machine::Ext<'a, HashFor, NumberFor, TrieBackend>; +type Ext<'a, B> = sp_state_machine::Ext<'a, HashFor, TrieBackend>; fn with_externalities R, R>(f: F) -> R { sp_externalities::with_externalities(f).expect("Environmental externalities not set.") @@ -68,7 +68,7 @@ where // Uncompress let mut db = MemoryDB::default(); - let root = match sp_trie::decode_compact::>, _, _>( + let root = match sp_trie::decode_compact::>, _, _>( &mut db, storage_proof.iter_compact_encoded_nodes(), Some(parent_head.state_root()), @@ -89,7 +89,6 @@ where sp_io::storage::host_clear.replace_implementation(host_storage_clear), sp_io::storage::host_root.replace_implementation(host_storage_root), sp_io::storage::host_clear_prefix.replace_implementation(host_storage_clear_prefix), - sp_io::storage::host_changes_root.replace_implementation(host_storage_changes_root), sp_io::storage::host_append.replace_implementation(host_storage_append), sp_io::storage::host_next_key.replace_implementation(host_storage_next_key), sp_io::storage::host_start_transaction @@ -162,6 +161,13 @@ where let horizontal_messages = crate::HrmpOutboundMessages::::get(); let hrmp_watermark = crate::HrmpWatermark::::get(); + let head_data = + if let Some(custom_head_data) = crate::CustomValidationHeadData::::get() { + HeadData(custom_head_data) + } else { + head_data + }; + ValidationResult { head_data, new_validation_code: new_validation_code.map(Into::into), @@ -215,8 +221,8 @@ fn host_storage_clear(key: &[u8]) { with_externalities(|ext| ext.place_storage(key.to_vec(), None)) } -fn host_storage_root() -> Vec { - with_externalities(|ext| ext.storage_root()) +fn host_storage_root(version: StateVersion) -> Vec { + with_externalities(|ext| ext.storage_root(version)) } fn host_storage_clear_prefix(prefix: &[u8], limit: Option) -> KillStorageResult { @@ -229,10 +235,6 @@ fn host_storage_clear_prefix(prefix: &[u8], limit: Option) -> KillStorageRe }) } -fn host_storage_changes_root(parent_hash: &[u8]) -> Option> { - with_externalities(|ext| ext.storage_changes_root(parent_hash).ok().flatten()) -} - fn host_storage_append(key: &[u8], value: Vec) { with_externalities(|ext| ext.storage_append(key.to_vec(), value)) } @@ -325,9 +327,9 @@ fn host_default_child_storage_clear_prefix( }) } -fn host_default_child_storage_root(storage_key: &[u8]) -> Vec { +fn host_default_child_storage_root(storage_key: &[u8], version: StateVersion) -> Vec { let child_info = ChildInfo::new_default(storage_key); - with_externalities(|ext| ext.child_storage_root(&child_info)) + with_externalities(|ext| ext.child_storage_root(&child_info, version)) } fn host_default_child_storage_next_key(storage_key: &[u8], key: &[u8]) -> Option> { diff --git a/pallets/parachain-system/src/validate_block/tests.rs b/pallets/parachain-system/src/validate_block/tests.rs index 5414e717d3..6453b9cd39 100644 --- a/pallets/parachain-system/src/validate_block/tests.rs +++ b/pallets/parachain-system/src/validate_block/tests.rs @@ -17,7 +17,8 @@ use codec::{Decode, Encode}; use cumulus_primitives_core::{ParachainBlockData, PersistedValidationData}; use cumulus_test_client::{ - runtime::{Block, Hash, Header, UncheckedExtrinsic, WASM_BINARY}, + generate_extrinsic, + runtime::{Block, Hash, Header, TestPalletCall, UncheckedExtrinsic, WASM_BINARY}, transfer, BlockData, BuildParachainBlockData, Client, DefaultTestClientBuilderExt, HeadData, InitBlockBuilder, TestClientBuilder, TestClientBuilderExt, ValidationParams, }; @@ -26,11 +27,11 @@ use sp_keyring::AccountKeyring::*; use sp_runtime::{generic::BlockId, traits::Header as HeaderT}; use std::{env, process::Command}; -fn call_validate_block( +fn call_validate_block_encoded_header( parent_head: Header, block_data: ParachainBlockData, relay_parent_storage_root: Hash, -) -> cumulus_test_client::ExecutorResult

{ +) -> cumulus_test_client::ExecutorResult> { cumulus_test_client::validate_block( ValidationParams { block_data: BlockData(block_data.encode()), @@ -40,7 +41,16 @@ fn call_validate_block( }, &WASM_BINARY.expect("You need to build the WASM binaries to run the tests!"), ) - .map(|v| Header::decode(&mut &v.head_data.0[..]).expect("Decodes `Header`.")) + .map(|v| v.head_data.0) +} + +fn call_validate_block( + parent_head: Header, + block_data: ParachainBlockData, + relay_parent_storage_root: Hash, +) -> cumulus_test_client::ExecutorResult
{ + call_validate_block_encoded_header(parent_head, block_data, relay_parent_storage_root) + .map(|v| Header::decode(&mut &v[..]).expect("Decodes `Header`.")) } fn create_test_client() -> (Client, Header) { @@ -92,7 +102,7 @@ fn validate_block_no_extra_extrinsics() { let (client, parent_head) = create_test_client(); let TestBlockData { block, validation_data } = - build_block_with_witness(&client, vec![], parent_head.clone(), Default::default()); + build_block_with_witness(&client, Vec::new(), parent_head.clone(), Default::default()); let header = block.header().clone(); let res_header = @@ -126,6 +136,43 @@ fn validate_block_with_extra_extrinsics() { assert_eq!(header, res_header); } +#[test] +fn validate_block_returns_custom_head_data() { + sp_tracing::try_init_simple(); + + let expected_header = vec![1, 3, 3, 7, 4, 5, 6]; + + let (client, parent_head) = create_test_client(); + let extra_extrinsics = vec![ + transfer(&client, Alice, Bob, 69), + generate_extrinsic( + &client, + Charlie, + TestPalletCall::set_custom_validation_head_data { + custom_header: expected_header.clone(), + }, + ), + transfer(&client, Bob, Charlie, 100), + ]; + + let TestBlockData { block, validation_data } = build_block_with_witness( + &client, + extra_extrinsics, + parent_head.clone(), + Default::default(), + ); + let header = block.header().clone(); + assert_ne!(expected_header, header.encode()); + + let res_header = call_validate_block_encoded_header( + parent_head, + block, + validation_data.relay_parent_storage_root, + ) + .expect("Calls `validate_block`"); + assert_eq!(expected_header, res_header); +} + #[test] fn validate_block_invalid_parent_hash() { sp_tracing::try_init_simple(); @@ -133,7 +180,7 @@ fn validate_block_invalid_parent_hash() { if env::var("RUN_TEST").is_ok() { let (client, parent_head) = create_test_client(); let TestBlockData { block, validation_data } = - build_block_with_witness(&client, vec![], parent_head.clone(), Default::default()); + build_block_with_witness(&client, Vec::new(), parent_head.clone(), Default::default()); let (mut header, extrinsics, witness) = block.deconstruct(); header.set_parent_hash(Hash::from_low_u64_be(1)); @@ -159,7 +206,7 @@ fn validate_block_fails_on_invalid_validation_data() { if env::var("RUN_TEST").is_ok() { let (client, parent_head) = create_test_client(); let TestBlockData { block, .. } = - build_block_with_witness(&client, vec![], parent_head.clone(), Default::default()); + build_block_with_witness(&client, Vec::new(), parent_head.clone(), Default::default()); call_validate_block(parent_head, block, Hash::random()).unwrap_err(); } else { @@ -184,7 +231,7 @@ fn check_inherent_fails_on_validate_block_as_expected() { let TestBlockData { block, validation_data } = build_block_with_witness( &client, - vec![], + Vec::new(), parent_head.clone(), RelayStateSproofBuilder { current_slot: 1337.into(), ..Default::default() }, ); diff --git a/pallets/session-benchmarking/Cargo.toml b/pallets/session-benchmarking/Cargo.toml index 2591325282..14c9c8f5ce 100644 --- a/pallets/session-benchmarking/Cargo.toml +++ b/pallets/session-benchmarking/Cargo.toml @@ -2,7 +2,7 @@ name = "cumulus-pallet-session-benchmarking" version = "3.0.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/cumulus/" @@ -13,21 +13,23 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-std = { default-features = false, git = 'https://github.com/paritytech/substrate', branch = "master" } -sp-runtime = { default-features = false, git = 'https://github.com/paritytech/substrate', branch = "master" } -frame-support = { default-features = false, git = 'https://github.com/paritytech/substrate', branch = "master" } -frame-system = { default-features = false, git = 'https://github.com/paritytech/substrate', branch = "master" } -frame-benchmarking = { default-features = false, optional = true, git = 'https://github.com/paritytech/substrate', branch = "master" } -pallet-session = { default-features = false, git = 'https://github.com/paritytech/substrate', branch = "master" } +parity-scale-codec = { version = "2.3.1", default-features = false } +sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" } +sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" } +frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" } +frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" } +frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "master" } +pallet-session = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" } [features] default = ["std"] runtime-benchmarks = [ - 'frame-benchmarking', - 'frame-support/runtime-benchmarks', - 'frame-system/runtime-benchmarks', + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", ] std = [ + "parity-scale-codec/std", "sp-std/std", "sp-runtime/std", "frame-system/std", diff --git a/pallets/session-benchmarking/src/lib.rs b/pallets/session-benchmarking/src/lib.rs index 533cc01d3c..5217bbae71 100644 --- a/pallets/session-benchmarking/src/lib.rs +++ b/pallets/session-benchmarking/src/lib.rs @@ -18,9 +18,10 @@ #![cfg(feature = "runtime-benchmarks")] use sp_std::{prelude::*, vec}; -use frame_benchmarking::{benchmarks, impl_benchmark_test_suite, whitelisted_caller}; +use frame_benchmarking::{benchmarks, whitelisted_caller}; use frame_system::RawOrigin; use pallet_session::*; +use parity_scale_codec::Decode; pub struct Pallet(pallet_session::Pallet); pub trait Config: pallet_session::Config {} @@ -28,17 +29,15 @@ benchmarks! { set_keys { let caller: T::AccountId = whitelisted_caller(); frame_system::Pallet::::inc_providers(&caller); - let keys = T::Keys::default(); + let keys = T::Keys::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes()).unwrap(); let proof: Vec = vec![0,1,2,3]; }: _(RawOrigin::Signed(caller), keys, proof) purge_keys { let caller: T::AccountId = whitelisted_caller(); frame_system::Pallet::::inc_providers(&caller); - let keys = T::Keys::default(); + let keys = T::Keys::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes()).unwrap(); let proof: Vec = vec![0,1,2,3]; let _t = pallet_session::Pallet::::set_keys(RawOrigin::Signed(caller.clone()).into(), keys, proof); }: _(RawOrigin::Signed(caller)) - } -impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test, extra = false,); diff --git a/pallets/xcm/Cargo.toml b/pallets/xcm/Cargo.toml index e56b47a990..3e7e2740d9 100644 --- a/pallets/xcm/Cargo.toml +++ b/pallets/xcm/Cargo.toml @@ -1,13 +1,13 @@ [package] authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" name = "cumulus-pallet-xcm" version = "0.1.0" [dependencies] codec = { package = "parity-scale-codec", version = "2.3.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.101", optional = true, features = ["derive"] } +serde = { version = "1.0.132", optional = true, features = ["derive"] } sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } sp-io = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } diff --git a/pallets/xcmp-queue/Cargo.toml b/pallets/xcmp-queue/Cargo.toml index 0ee1751139..974552e7be 100644 --- a/pallets/xcmp-queue/Cargo.toml +++ b/pallets/xcmp-queue/Cargo.toml @@ -2,7 +2,7 @@ name = "cumulus-pallet-xcmp-queue" version = "0.1.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" [dependencies] # Other dependencies @@ -25,11 +25,11 @@ xcm-executor = { git = "https://github.com/paritytech/polkadot", default-feature cumulus-primitives-core = { path = "../../primitives/core", default-features = false } [dev-dependencies] -sp-core = { git = 'https://github.com/paritytech/substrate', branch = "master" } -sp-io = { git = 'https://github.com/paritytech/substrate', branch = "master" } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-io = { git = "https://github.com/paritytech/substrate", branch = "master" } cumulus-pallet-parachain-system = { path = "../parachain-system" } xcm-builder = { git = "https://github.com/paritytech/polkadot", branch = "master" } -pallet-balances = { git = 'https://github.com/paritytech/substrate', branch = "master" } +pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master" } [features] default = [ "std" ] diff --git a/pallets/xcmp-queue/src/lib.rs b/pallets/xcmp-queue/src/lib.rs index 378bfe383e..cab3a18e42 100644 --- a/pallets/xcmp-queue/src/lib.rs +++ b/pallets/xcmp-queue/src/lib.rs @@ -25,6 +25,8 @@ #![cfg_attr(not(feature = "std"), no_std)] +pub mod migration; + #[cfg(test)] mod mock; @@ -36,7 +38,7 @@ use cumulus_primitives_core::{ relay_chain::BlockNumber as RelayBlockNumber, ChannelStatus, GetChannelInfo, MessageSendError, ParaId, XcmpMessageFormat, XcmpMessageHandler, XcmpMessageSource, }; -use frame_support::weights::Weight; +use frame_support::weights::{constants::WEIGHT_PER_MILLIS, Weight}; use rand_chacha::{ rand_core::{RngCore, SeedableRng}, ChaChaRng, @@ -48,6 +50,11 @@ use xcm::{latest::prelude::*, VersionedXcm, WrapVersion, MAX_XCM_DECODE_DEPTH}; pub use pallet::*; +/// Index used to identify overweight XCMs. +pub type OverweightIndex = u64; + +const LOG_TARGET: &str = "xcmp_queue"; + #[frame_support::pallet] pub mod pallet { use super::*; @@ -56,6 +63,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] + #[pallet::storage_version(migration::STORAGE_VERSION)] pub struct Pallet(_); #[pallet::config] @@ -70,22 +78,17 @@ pub mod pallet { /// Means of converting an `Xcm` into a `VersionedXcm`. type VersionWrapper: WrapVersion; - } - impl Default for QueueConfigData { - fn default() -> Self { - Self { - suspend_threshold: 2, - drop_threshold: 5, - resume_threshold: 1, - threshold_weight: 100_000, - weight_restrict_decay: 2, - } - } + /// The origin that is allowed to execute overweight messages. + type ExecuteOverweightOrigin: EnsureOrigin; } #[pallet::hooks] impl Hooks> for Pallet { + fn on_runtime_upgrade() -> Weight { + migration::migrate_to_latest::() + } + fn on_idle(_now: T::BlockNumber, max_weight: Weight) -> Weight { // on_idle processes additional messages with any remaining block weight. Self::service_xcmp_queue(max_weight) @@ -93,7 +96,40 @@ pub mod pallet { } #[pallet::call] - impl Pallet {} + impl Pallet { + /// Services a single overweight XCM. + /// + /// - `origin`: Must pass `ExecuteOverweightOrigin`. + /// - `index`: The index of the overweight XCM to service + /// - `weight_limit`: The amount of weight that XCM execution may take. + /// + /// Errors: + /// - `BadOverweightIndex`: XCM under `index` is not found in the `Overweight` storage map. + /// - `BadXcm`: XCM under `index` cannot be properly decoded into a valid XCM format. + /// - `WeightOverLimit`: XCM execution may use greater `weight_limit`. + /// + /// Events: + /// - `OverweightServiced`: On success. + #[pallet::weight(weight_limit.saturating_add(1_000_000))] + pub fn service_overweight( + origin: OriginFor, + index: OverweightIndex, + weight_limit: Weight, + ) -> DispatchResultWithPostInfo { + T::ExecuteOverweightOrigin::ensure_origin(origin)?; + + let (sender, sent_at, data) = + Overweight::::get(index).ok_or(Error::::BadOverweightIndex)?; + let xcm = + VersionedXcm::::decode_all_with_depth_limit(MAX_XCM_DECODE_DEPTH, &data) + .map_err(|_| Error::::BadXcm)?; + let used = Self::handle_xcm_message(sender, sent_at, xcm, weight_limit) + .map_err(|_| Error::::WeightOverLimit)?; + Overweight::::remove(index); + Self::deposit_event(Event::OverweightServiced(index, used)); + Ok(Some(used.saturating_add(1_000_000)).into()) + } + } #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] @@ -110,6 +146,10 @@ pub mod pallet { UpwardMessageSent(Option), /// An HRMP message was sent to a sibling parachain. XcmpMessageSent(Option), + /// An XCM exceeded the individual message weight budget. + OverweightEnqueued(ParaId, RelayBlockNumber, OverweightIndex, Weight), + /// An XCM from the overweight queue was executed with the given actual weight used. + OverweightServiced(OverweightIndex, Weight), } #[pallet::error] @@ -120,15 +160,16 @@ pub mod pallet { BadXcmOrigin, /// Bad XCM data. BadXcm, + /// Bad overweight index. + BadOverweightIndex, + /// Provided weight is possibly not enough to execute the message. + WeightOverLimit, } /// Status of the inbound XCMP channels. #[pallet::storage] - pub(super) type InboundXcmpStatus = StorageValue< - _, - Vec<(ParaId, InboundStatus, Vec<(RelayBlockNumber, XcmpMessageFormat)>)>, - ValueQuery, - >; + pub(super) type InboundXcmpStatus = + StorageValue<_, Vec, ValueQuery>; /// Inbound aggregate XCMP messages. It can only be one per ParaId/block. #[pallet::storage] @@ -150,7 +191,7 @@ pub mod pallet { /// The bool is true if there is a signal message waiting to be sent. #[pallet::storage] pub(super) type OutboundXcmpStatus = - StorageValue<_, Vec<(ParaId, OutboundStatus, bool, u16, u16)>, ValueQuery>; + StorageValue<_, Vec, ValueQuery>; // The new way of doing it: /// The messages outbound in a given XCMP channel. @@ -166,20 +207,84 @@ pub mod pallet { /// The configuration which controls the dynamics of the outbound queue. #[pallet::storage] pub(super) type QueueConfig = StorageValue<_, QueueConfigData, ValueQuery>; + + /// The messages that exceeded max individual message weight budget. + /// + /// These message stay in this storage map until they are manually dispatched via + /// `service_overweight`. + #[pallet::storage] + pub(super) type Overweight = + StorageMap<_, Twox64Concat, OverweightIndex, (ParaId, RelayBlockNumber, Vec)>; + + /// The number of overweight messages ever recorded in `Overweight`. Also doubles as the next + /// available free overweight index. + #[pallet::storage] + pub(super) type OverweightCount = StorageValue<_, OverweightIndex, ValueQuery>; } #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, RuntimeDebug, TypeInfo)] -pub enum InboundStatus { +pub enum InboundState { Ok, Suspended, } #[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] -pub enum OutboundStatus { +pub enum OutboundState { Ok, Suspended, } +/// Struct containing detailed information about the inbound channel. +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub struct InboundChannelDetails { + /// The `ParaId` of the parachain that this channel is connected with. + sender: ParaId, + /// The state of the channel. + state: InboundState, + /// The ordered metadata of each inbound message. + /// + /// Contains info about the relay block number that the message was sent at, and the format + /// of the incoming message. + message_metadata: Vec<(RelayBlockNumber, XcmpMessageFormat)>, +} + +/// Struct containing detailed information about the outbound channel. +#[derive(Clone, Eq, PartialEq, Encode, Decode, TypeInfo)] +pub struct OutboundChannelDetails { + /// The `ParaId` of the parachain that this channel is connected with. + recipient: ParaId, + /// The state of the channel. + state: OutboundState, + /// Whether or not any signals exist in this channel. + signals_exist: bool, + /// The index of the first outbound message. + first_index: u16, + /// The index of the last outbound message. + last_index: u16, +} + +impl OutboundChannelDetails { + pub fn new(recipient: ParaId) -> OutboundChannelDetails { + OutboundChannelDetails { + recipient, + state: OutboundState::Ok, + signals_exist: false, + first_index: 0, + last_index: 0, + } + } + + pub fn with_signals(mut self) -> OutboundChannelDetails { + self.signals_exist = true; + self + } + + pub fn with_suspended_state(mut self) -> OutboundChannelDetails { + self.state = OutboundState::Suspended; + self + } +} + #[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct QueueConfigData { /// The number of pages of messages which must be in the queue for the other side to be told to @@ -196,6 +301,22 @@ pub struct QueueConfigData { /// The speed to which the available weight approaches the maximum weight. A lower number /// results in a faster progression. A value of 1 makes the entire weight available initially. weight_restrict_decay: Weight, + /// The maximum amount of weight any individual message may consume. Messages above this weight + /// go into the overweight queue and may only be serviced explicitly. + xcmp_max_individual_weight: Weight, +} + +impl Default for QueueConfigData { + fn default() -> Self { + Self { + suspend_threshold: 2, + drop_threshold: 5, + resume_threshold: 1, + threshold_weight: 100_000, + weight_restrict_decay: 2, + xcmp_max_individual_weight: 20 * WEIGHT_PER_MILLIS, + } + } } #[derive(PartialEq, Eq, Copy, Clone, Encode, Decode, TypeInfo)] @@ -242,13 +363,13 @@ impl Pallet { } let mut s = >::get(); - let index = s.iter().position(|item| item.0 == recipient).unwrap_or_else(|| { - s.push((recipient, OutboundStatus::Ok, false, 0, 0)); + let index = s.iter().position(|item| item.recipient == recipient).unwrap_or_else(|| { + s.push(OutboundChannelDetails::new(recipient)); s.len() - 1 }); - let have_active = s[index].4 > s[index].3; + let have_active = s[index].last_index > s[index].first_index; let appended = have_active && - >::mutate(recipient, s[index].4 - 1, |s| { + >::mutate(recipient, s[index].last_index - 1, |s| { if XcmpMessageFormat::decode_and_advance_with_depth_limit( MAX_XCM_DECODE_DEPTH, &mut &s[..], @@ -263,15 +384,15 @@ impl Pallet { return true }); if appended { - Ok((s[index].4 - s[index].3 - 1) as u32) + Ok((s[index].last_index - s[index].first_index - 1) as u32) } else { // Need to add a new page. - let page_index = s[index].4; - s[index].4 += 1; + let page_index = s[index].last_index; + s[index].last_index += 1; let mut new_page = format.encode(); new_page.extend_from_slice(&data[..]); >::insert(recipient, page_index, new_page); - let r = (s[index].4 - s[index].3 - 1) as u32; + let r = (s[index].last_index - s[index].first_index - 1) as u32; >::put(s); Ok(r) } @@ -281,10 +402,10 @@ impl Pallet { /// block. fn send_signal(dest: ParaId, signal: ChannelSignal) -> Result<(), ()> { let mut s = >::get(); - if let Some(index) = s.iter().position(|item| item.0 == dest) { - s[index].2 = true; + if let Some(index) = s.iter().position(|item| item.recipient == dest) { + s[index].signals_exist = true; } else { - s.push((dest, OutboundStatus::Ok, true, 0, 0)); + s.push(OutboundChannelDetails::new(dest).with_signals()); } >::mutate(dest, |page| { if page.is_empty() { @@ -366,6 +487,7 @@ impl Pallet { sender: ParaId, (sent_at, format): (RelayBlockNumber, XcmpMessageFormat), max_weight: Weight, + max_individual_weight: Weight, ) -> (Weight, bool) { let data = >::get(sender, sent_at); let mut last_remaining_fragments; @@ -382,7 +504,22 @@ impl Pallet { let weight = max_weight - weight_used; match Self::handle_xcm_message(sender, sent_at, xcm, weight) { Ok(used) => weight_used = weight_used.saturating_add(used), - Err(XcmError::TooMuchWeightRequired) => { + Err(XcmError::WeightLimitReached(required)) + if required > max_individual_weight => + { + // overweight - add to overweight queue and continue with message + // execution consuming the message. + let msg_len = last_remaining_fragments + .len() + .saturating_sub(remaining_fragments.len()); + let overweight_xcm = last_remaining_fragments[..msg_len].to_vec(); + let index = Self::stash_overweight(sender, sent_at, overweight_xcm); + let e = Event::OverweightEnqueued(sender, sent_at, index, required); + Self::deposit_event(e); + }, + Err(XcmError::WeightLimitReached(required)) + if required <= max_weight => + { // That message didn't get processed this time because of being // too heavy. We leave it around for next time and bail. remaining_fragments = last_remaining_fragments; @@ -438,6 +575,22 @@ impl Pallet { (weight_used, is_empty) } + /// Puts a given XCM into the list of overweight messages, allowing it to be executed later. + fn stash_overweight( + sender: ParaId, + sent_at: RelayBlockNumber, + xcm: Vec, + ) -> OverweightIndex { + let index = ::OverweightCount::mutate(|count| { + let index = *count; + *count += 1; + index + }); + + ::Overweight::insert(index, (sender, sent_at, xcm)); + index + } + /// Service the incoming XCMP message queue attempting to execute up to `max_weight` execution /// weight of messages. /// @@ -471,8 +624,13 @@ impl Pallet { return 0 } - let QueueConfigData { resume_threshold, threshold_weight, weight_restrict_decay, .. } = - >::get(); + let QueueConfigData { + resume_threshold, + threshold_weight, + weight_restrict_decay, + xcmp_max_individual_weight, + .. + } = >::get(); let mut shuffled = Self::create_shuffle(status.len()); let mut weight_used = 0; @@ -491,7 +649,7 @@ impl Pallet { max_weight.saturating_sub(weight_used) >= threshold_weight { let index = shuffled[shuffle_index]; - let sender = status[index].0; + let sender = status[index].sender; if weight_available != max_weight { // Get incrementally closer to freeing up max_weight for message execution over the @@ -508,34 +666,38 @@ impl Pallet { } } - let weight_processed = if status[index].2.is_empty() { + let weight_processed = if status[index].message_metadata.is_empty() { debug_assert!(false, "channel exists in status; there must be messages; qed"); 0 } else { // Process up to one block's worth for now. let weight_remaining = weight_available.saturating_sub(weight_used); - let (weight_processed, is_empty) = - Self::process_xcmp_message(sender, status[index].2[0], weight_remaining); + let (weight_processed, is_empty) = Self::process_xcmp_message( + sender, + status[index].message_metadata[0], + weight_remaining, + xcmp_max_individual_weight, + ); if is_empty { - status[index].2.remove(0); + status[index].message_metadata.remove(0); } weight_processed }; weight_used += weight_processed; - if status[index].2.len() as u32 <= resume_threshold && - status[index].1 == InboundStatus::Suspended + if status[index].message_metadata.len() as u32 <= resume_threshold && + status[index].state == InboundState::Suspended { // Resume let r = Self::send_signal(sender, ChannelSignal::Resume); debug_assert!(r.is_ok(), "WARNING: Failed sending resume into suspended channel"); - status[index].1 = InboundStatus::Ok; + status[index].state = InboundState::Ok; } // If there are more and we're making progress, we process them after we've given the // other channels a look in. If we've still not unlocked all weight, then we set them // up for processing a second time anyway. - if !status[index].2.is_empty() && + if !status[index].message_metadata.is_empty() && (weight_processed > 0 || weight_available != max_weight) { if shuffle_index + 1 == shuffled.len() { @@ -548,7 +710,7 @@ impl Pallet { } // Only retain the senders that have non-empty queues. - status.retain(|item| !item.2.is_empty()); + status.retain(|item| !item.message_metadata.is_empty()); >::put(status); weight_used @@ -556,28 +718,28 @@ impl Pallet { fn suspend_channel(target: ParaId) { >::mutate(|s| { - if let Some(index) = s.iter().position(|item| item.0 == target) { - let ok = s[index].1 == OutboundStatus::Ok; + if let Some(index) = s.iter().position(|item| item.recipient == target) { + let ok = s[index].state == OutboundState::Ok; debug_assert!(ok, "WARNING: Attempt to suspend channel that was not Ok."); - s[index].1 = OutboundStatus::Suspended; + s[index].state = OutboundState::Suspended; } else { - s.push((target, OutboundStatus::Suspended, false, 0, 0)); + s.push(OutboundChannelDetails::new(target).with_suspended_state()); } }); } fn resume_channel(target: ParaId) { >::mutate(|s| { - if let Some(index) = s.iter().position(|item| item.0 == target) { - let suspended = s[index].1 == OutboundStatus::Suspended; + if let Some(index) = s.iter().position(|item| item.recipient == target) { + let suspended = s[index].state == OutboundState::Suspended; debug_assert!( suspended, "WARNING: Attempt to resume channel that was not suspended." ); - if s[index].3 == s[index].4 { + if s[index].first_index == s[index].last_index { s.remove(index); } else { - s[index].1 = OutboundStatus::Ok; + s[index].state = OutboundState::Ok; } } else { debug_assert!(false, "WARNING: Attempt to resume channel that was not suspended."); @@ -619,11 +781,12 @@ impl XcmpMessageHandler for Pallet { } } else { // Record the fact we received it. - match status.binary_search_by_key(&sender, |item| item.0) { + match status.binary_search_by_key(&sender, |item| item.sender) { Ok(i) => { - let count = status[i].2.len(); - if count as u32 >= suspend_threshold && status[i].1 == InboundStatus::Ok { - status[i].1 = InboundStatus::Suspended; + let count = status[i].message_metadata.len(); + if count as u32 >= suspend_threshold && status[i].state == InboundState::Ok + { + status[i].state = InboundState::Suspended; let r = Self::send_signal(sender, ChannelSignal::Suspend); if r.is_err() { log::warn!( @@ -632,7 +795,7 @@ impl XcmpMessageHandler for Pallet { } } if (count as u32) < drop_threshold { - status[i].2.push((sent_at, format)); + status[i].message_metadata.push((sent_at, format)); } else { debug_assert!( false, @@ -640,7 +803,11 @@ impl XcmpMessageHandler for Pallet { ); } }, - Err(_) => status.push((sender, InboundStatus::Ok, vec![(sent_at, format)])), + Err(_) => status.push(InboundChannelDetails { + sender, + state: InboundState::Ok, + message_metadata: vec![(sent_at, format)], + }), } // Queue the payload for later execution. >::insert(sender, sent_at, data_ref); @@ -664,47 +831,53 @@ impl XcmpMessageSource for Pallet { let mut result = Vec::with_capacity(max_message_count); for status in statuses.iter_mut() { - let (para_id, outbound_status, mut signalling, mut begin, mut end) = *status; + let OutboundChannelDetails { + recipient: para_id, + state: outbound_state, + mut signals_exist, + mut first_index, + mut last_index, + } = *status; if result.len() == max_message_count { // We check this condition in the beginning of the loop so that we don't include // a message where the limit is 0. break } - if outbound_status == OutboundStatus::Suspended { + if outbound_state == OutboundState::Suspended { continue } let (max_size_now, max_size_ever) = match T::ChannelInfo::get_channel_status(para_id) { ChannelStatus::Closed => { // This means that there is no such channel anymore. Nothing to be done but // swallow the messages and discard the status. - for i in begin..end { + for i in first_index..last_index { >::remove(para_id, i); } - if signalling { + if signals_exist { >::remove(para_id); } - *status = (para_id, OutboundStatus::Ok, false, 0, 0); + *status = OutboundChannelDetails::new(para_id); continue }, ChannelStatus::Full => continue, ChannelStatus::Ready(n, e) => (n, e), }; - let page = if signalling { + let page = if signals_exist { let page = >::get(para_id); if page.len() < max_size_now { >::remove(para_id); - signalling = false; + signals_exist = false; page } else { continue } - } else if end > begin { - let page = >::get(para_id, begin); + } else if last_index > first_index { + let page = >::get(para_id, first_index); if page.len() < max_size_now { - >::remove(para_id, begin); - begin += 1; + >::remove(para_id, first_index); + first_index += 1; page } else { continue @@ -712,9 +885,9 @@ impl XcmpMessageSource for Pallet { } else { continue }; - if begin == end { - begin = 0; - end = 0; + if first_index == last_index { + first_index = 0; + last_index = 0; } if page.len() > max_size_ever { @@ -726,7 +899,13 @@ impl XcmpMessageSource for Pallet { result.push((para_id, page)); } - *status = (para_id, outbound_status, signalling, begin, end); + *status = OutboundChannelDetails { + recipient: para_id, + state: outbound_state, + signals_exist, + first_index, + last_index, + }; } // Sort the outbound messages by ascending recipient para id to satisfy the acceptance @@ -741,7 +920,9 @@ impl XcmpMessageSource for Pallet { // // To mitigate this we shift all processed elements towards the end of the vector using // `rotate_left`. To get intuition how it works see the examples in its rustdoc. - statuses.retain(|x| x.1 == OutboundStatus::Suspended || x.2 || x.3 < x.4); + statuses.retain(|x| { + x.state == OutboundState::Suspended || x.signals_exist || x.first_index < x.last_index + }); // old_status_len must be >= status.len() since we never add anything to status. let pruned = old_statuses_len - statuses.len(); diff --git a/pallets/xcmp-queue/src/migration.rs b/pallets/xcmp-queue/src/migration.rs new file mode 100644 index 0000000000..db5833e2df --- /dev/null +++ b/pallets/xcmp-queue/src/migration.rs @@ -0,0 +1,128 @@ +// Copyright 2021 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 module that is responsible for migration of storage. + +use crate::{Config, Pallet, Store}; +use frame_support::{pallet_prelude::*, traits::StorageVersion, weights::Weight}; + +/// The current storage version. +pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + +/// Migrates the pallet storage to the most recent version, checking and setting the +/// `StorageVersion`. +pub fn migrate_to_latest() -> Weight { + let mut weight = 0; + + if StorageVersion::get::>() == 0 { + weight += migrate_to_v1::(); + StorageVersion::new(1).put::>(); + } + + weight +} + +mod v0 { + use super::*; + use codec::{Decode, Encode}; + + #[derive(Encode, Decode, Debug)] + pub struct QueueConfigData { + pub suspend_threshold: u32, + pub drop_threshold: u32, + pub resume_threshold: u32, + pub threshold_weight: Weight, + pub weight_restrict_decay: Weight, + } + + impl Default for QueueConfigData { + fn default() -> Self { + QueueConfigData { + suspend_threshold: 2, + drop_threshold: 5, + resume_threshold: 1, + threshold_weight: 100_000, + weight_restrict_decay: 2, + } + } + } +} + +/// Migrates `QueueConfigData` from v0 (without the `xcmp_max_individual_weight` field) to v1 (with +/// max individual weight). +/// Uses the `Default` implementation of `QueueConfigData` to choose a value for +/// `xcmp_max_individual_weight`. +/// +/// NOTE: Only use this function if you know what you're doing. Default to using +/// `migrate_to_latest`. +pub fn migrate_to_v1() -> Weight { + let translate = |pre: v0::QueueConfigData| -> super::QueueConfigData { + super::QueueConfigData { + suspend_threshold: pre.suspend_threshold, + drop_threshold: pre.drop_threshold, + resume_threshold: pre.resume_threshold, + threshold_weight: pre.threshold_weight, + weight_restrict_decay: pre.weight_restrict_decay, + xcmp_max_individual_weight: super::QueueConfigData::default() + .xcmp_max_individual_weight, + } + }; + + if let Err(_) = as Store>::QueueConfig::translate(|pre| pre.map(translate)) { + log::error!( + target: super::LOG_TARGET, + "unexpected error when performing translation of the QueueConfig type during storage upgrade to v1" + ); + } + + T::DbWeight::get().reads_writes(1, 1) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::mock::{new_test_ext, Test}; + + #[test] + fn test_migration_to_v1() { + let v0 = v0::QueueConfigData { + suspend_threshold: 5, + drop_threshold: 12, + resume_threshold: 3, + threshold_weight: 333_333, + weight_restrict_decay: 1, + }; + + new_test_ext().execute_with(|| { + // Put the v0 version in the state + frame_support::storage::unhashed::put_raw( + &crate::QueueConfig::::hashed_key(), + &v0.encode(), + ); + + migrate_to_v1::(); + + let v1 = crate::QueueConfig::::get(); + + assert_eq!(v0.suspend_threshold, v1.suspend_threshold); + assert_eq!(v0.drop_threshold, v1.drop_threshold); + assert_eq!(v0.resume_threshold, v1.resume_threshold); + assert_eq!(v0.threshold_weight, v1.threshold_weight); + assert_eq!(v0.weight_restrict_decay, v1.weight_restrict_decay); + assert_eq!(v1.xcmp_max_individual_weight, 20_000_000_000); + }); + } +} diff --git a/pallets/xcmp-queue/src/mock.rs b/pallets/xcmp-queue/src/mock.rs index c0dea9bd1f..7c8d80dd9d 100644 --- a/pallets/xcmp-queue/src/mock.rs +++ b/pallets/xcmp-queue/src/mock.rs @@ -16,6 +16,7 @@ use super::*; use crate as xcmp_queue; use frame_support::parameter_types; +use frame_system::EnsureRoot; use sp_core::H256; use sp_runtime::{ testing::Header, @@ -75,6 +76,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = SS58Prefix; type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { @@ -160,6 +162,7 @@ impl Config for Test { type XcmExecutor = xcm_executor::XcmExecutor; type ChannelInfo = ParachainSystem; type VersionWrapper = (); + type ExecuteOverweightOrigin = EnsureRoot; } pub fn new_test_ext() -> sp_io::TestExternalities { diff --git a/pallets/xcmp-queue/src/tests.rs b/pallets/xcmp-queue/src/tests.rs index 9cc427848a..bb352e69ff 100644 --- a/pallets/xcmp-queue/src/tests.rs +++ b/pallets/xcmp-queue/src/tests.rs @@ -15,7 +15,8 @@ use super::*; use cumulus_primitives_core::XcmpMessageHandler; -use mock::{new_test_ext, Test, XcmpQueue}; +use frame_support::assert_noop; +use mock::{new_test_ext, Origin, Test, XcmpQueue}; #[test] fn one_message_does_not_panic() { @@ -30,6 +31,7 @@ fn one_message_does_not_panic() { #[test] #[should_panic = "Invalid incoming blob message data"] +#[cfg(debug_assertions)] fn bad_message_is_handled() { new_test_ext().execute_with(|| { let bad_data = vec![ @@ -40,12 +42,13 @@ fn bad_message_is_handled() { InboundXcmpMessages::::insert(ParaId::from(1000), 1, bad_data); let format = XcmpMessageFormat::ConcatenatedEncodedBlob; // This should exit with an error. - XcmpQueue::process_xcmp_message(1000.into(), (1, format), 10_000_000_000); + XcmpQueue::process_xcmp_message(1000.into(), (1, format), 10_000_000_000, 10_000_000_000); }); } #[test] #[should_panic = "Invalid incoming blob message data"] +#[cfg(debug_assertions)] fn other_bad_message_is_handled() { new_test_ext().execute_with(|| { let bad_data = vec![ @@ -56,6 +59,26 @@ fn other_bad_message_is_handled() { InboundXcmpMessages::::insert(ParaId::from(1000), 1, bad_data); let format = XcmpMessageFormat::ConcatenatedEncodedBlob; // This should exit with an error. - XcmpQueue::process_xcmp_message(1000.into(), (1, format), 10_000_000_000); + XcmpQueue::process_xcmp_message(1000.into(), (1, format), 10_000_000_000, 10_000_000_000); + }); +} + +#[test] +fn service_overweight_unknown() { + new_test_ext().execute_with(|| { + assert_noop!( + XcmpQueue::service_overweight(Origin::root(), 0, 1000), + Error::::BadOverweightIndex, + ); + }); +} + +#[test] +fn service_overweight_bad_xcm_format() { + new_test_ext().execute_with(|| { + let bad_xcm = vec![255]; + Overweight::::insert(0, (ParaId::from(1000), 0, bad_xcm)); + + assert_noop!(XcmpQueue::service_overweight(Origin::root(), 0, 1000), Error::::BadXcm); }); } diff --git a/parachain-template/README.md b/parachain-template/README.md index 1580521ccd..6dcc70c538 100644 --- a/parachain-template/README.md +++ b/parachain-template/README.md @@ -2,13 +2,21 @@ A new [Cumulus](https://github.com/paritytech/cumulus/)-based Substrate node, ready for hacking ☁️.. -This project is a fork of the [Substrate Node Template](https://github.com/substrate-developer-hub/substrate-node-template) +This project is originally a fork of the +[Substrate Node Template](https://github.com/substrate-developer-hub/substrate-node-template) modified to include dependencies required for registering this node as a **parathread** or -**parachain** to the Rococo **relay chain**. -Rococo is [Polkadot's parachain testnet](https://polkadot.network/blog/introducing-rococo-polkadots-parachain-testnet/) 👑. +**parachain** to a **relay chain**. + +The stand-alone version of this template is hosted on the +[Substrate Devhub Parachain Template](https://github.com/substrate-developer-hub/substrate-parachain-template/) +for each release of Polkadot. It is generated directly to the upstream +[Parachain Template in Cumulus](https://github.com/paritytech/cumulus/tree/master/parachain-template) +at each release branch using the +[Substrate Template Generator](https://github.com/paritytech/substrate-template-generator/). 👉 Learn more about parachains [here](https://wiki.polkadot.network/docs/learn-parachains), and parathreads [here](https://wiki.polkadot.network/docs/learn-parathreads). -To learn about how to actually use the template to hack together your own parachain check out the -`README` from the [`substrate-parachain-template` repository](https://github.com/substrate-developer-hub/substrate-parachain-template/). + +🧙 Learn about how to use this template and run your own parachain testnet for it in the +[Devhub Cumulus Tutorial](https://docs.substrate.io/tutorials/v3/cumulus/start-relay/). \ No newline at end of file diff --git a/parachain-template/node/Cargo.toml b/parachain-template/node/Cargo.toml index 58e10bae35..fd3c510d0f 100644 --- a/parachain-template/node/Cargo.toml +++ b/parachain-template/node/Cargo.toml @@ -6,7 +6,7 @@ description = "A new Cumulus FRAME-based Substrate Node, ready for hacking toget license = "Unlicense" homepage = "https://substrate.io" repository = "https://github.com/paritytech/cumulus/" -edition = "2018" +edition = "2021" build = "build.rs" [package.metadata.docs.rs] @@ -21,13 +21,14 @@ path = "src/main.rs" [features] runtime-benchmarks = ["parachain-template-runtime/runtime-benchmarks"] +try-runtime = [ "parachain-template-runtime/try-runtime" ] [dependencies] derive_more = "0.99.2" log = "0.4.14" codec = { package = "parity-scale-codec", version = "2.0.0" } structopt = "0.3.8" -serde = { version = "1.0.119", features = ["derive"] } +serde = { version = "1.0.132", features = ["derive"] } hex-literal = "0.3.1" # RPC related Dependencies @@ -39,6 +40,7 @@ parachain-template-runtime = { path = "../runtime" } # Substrate Dependencies frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master" } frame-benchmarking-cli = { git = "https://github.com/paritytech/substrate", branch = "master" } +try-runtime-cli = { git = "https://github.com/paritytech/substrate", branch = "master" } pallet-transaction-payment-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" } @@ -86,10 +88,12 @@ cumulus-client-network = { path = "../../client/network" } cumulus-client-service = { path = "../../client/service" } cumulus-primitives-core = { path = "../../primitives/core" } cumulus-primitives-parachain-inherent = { path = "../../primitives/parachain-inherent" } +cumulus-relay-chain-interface = { path = "../../client/relay-chain-interface" } +cumulus-relay-chain-local = { path = "../../client/relay-chain-local" } # Polkadot dependencies polkadot-cli = { git = "https://github.com/paritytech/polkadot", branch = "master" } polkadot-parachain = { git = "https://github.com/paritytech/polkadot", branch = "master" } polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "master" } polkadot-service = { git = "https://github.com/paritytech/polkadot", branch = "master" } -polkadot-test-service = { git = "https://github.com/paritytech/polkadot", branch = "master" } + diff --git a/parachain-template/node/src/chain_spec.rs b/parachain-template/node/src/chain_spec.rs index 1609bfb06c..24756264f4 100644 --- a/parachain-template/node/src/chain_spec.rs +++ b/parachain-template/node/src/chain_spec.rs @@ -11,7 +11,7 @@ pub type ChainSpec = sc_service::GenericChainSpec; /// Helper function to generate a crypto pair from seed -pub fn get_pair_from_seed(seed: &str) -> ::Public { +pub fn get_public_from_seed(seed: &str) -> ::Public { TPublic::Pair::from_string(&format!("//{}", seed), None) .expect("static values are valid; qed") .public() @@ -40,7 +40,7 @@ type AccountPublic = ::Signer; /// /// 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) -> AuraId { - get_pair_from_seed::(seed) + get_public_from_seed::(seed) } /// Helper function to generate an account ID from seed @@ -48,7 +48,7 @@ pub fn get_account_id_from_seed(seed: &str) -> AccountId where AccountPublic: From<::Public>, { - AccountPublic::from(get_pair_from_seed::(seed)).into_account() + AccountPublic::from(get_public_from_seed::(seed)).into_account() } /// Generate the session keys from individual elements. @@ -58,10 +58,10 @@ pub fn template_session_keys(keys: AuraId) -> parachain_template_runtime::Sessio parachain_template_runtime::SessionKeys { aura: keys } } -pub fn development_config(id: ParaId) -> ChainSpec { +pub fn development_config() -> ChainSpec { // 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("tokenSymbol".into(), "UNIT".into()); properties.insert("tokenDecimals".into(), 12.into()); properties.insert("ss58Format".into(), 42.into()); @@ -98,24 +98,24 @@ pub fn development_config(id: ParaId) -> ChainSpec { get_account_id_from_seed::("Eve//stash"), get_account_id_from_seed::("Ferdie//stash"), ], - id, + 1000.into(), ) }, - vec![], + Vec::new(), None, None, None, Extensions { relay_chain: "rococo-local".into(), // You MUST set this to the correct network! - para_id: id.into(), + para_id: 1000, }, ) } -pub fn local_testnet_config(id: ParaId) -> ChainSpec { +pub fn local_testnet_config() -> ChainSpec { // 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("tokenSymbol".into(), "UNIT".into()); properties.insert("tokenDecimals".into(), 12.into()); properties.insert("ss58Format".into(), 42.into()); @@ -152,11 +152,11 @@ pub fn local_testnet_config(id: ParaId) -> ChainSpec { get_account_id_from_seed::("Eve//stash"), get_account_id_from_seed::("Ferdie//stash"), ], - id, + 1000.into(), ) }, // Bootnodes - vec![], + Vec::new(), // Telemetry None, // Protocol ID @@ -166,7 +166,7 @@ pub fn local_testnet_config(id: ParaId) -> ChainSpec { // Extensions Extensions { relay_chain: "rococo-local".into(), // You MUST set this to the correct network! - para_id: id.into(), + para_id: 1000, }, ) } @@ -181,7 +181,6 @@ fn testnet_genesis( code: parachain_template_runtime::WASM_BINARY .expect("WASM binary was not build, please build it!") .to_vec(), - changes_trie_config: Default::default(), }, balances: parachain_template_runtime::BalancesConfig { balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(), @@ -194,8 +193,7 @@ fn testnet_genesis( }, session: parachain_template_runtime::SessionConfig { keys: invulnerables - .iter() - .cloned() + .into_iter() .map(|(acc, aura)| { ( acc.clone(), // account id diff --git a/parachain-template/node/src/cli.rs b/parachain-template/node/src/cli.rs index 319893a0c7..53040d7c58 100644 --- a/parachain-template/node/src/cli.rs +++ b/parachain-template/node/src/cli.rs @@ -37,6 +37,9 @@ pub enum Subcommand { /// The custom benchmark subcommmand benchmarking runtime pallets. #[structopt(name = "benchmark", about = "Benchmark runtime pallets.")] Benchmark(frame_benchmarking_cli::BenchmarkCmd), + + /// Try some testing command against a specified runtime state. + TryRuntime(try_runtime_cli::TryRuntimeCmd), } /// Command for exporting the genesis state of the parachain @@ -46,18 +49,12 @@ pub struct ExportGenesisStateCommand { #[structopt(parse(from_os_str))] pub output: Option, - /// Id of the parachain this state is for. - /// - /// Default: 100 - #[structopt(long, conflicts_with = "chain")] - pub parachain_id: Option, - /// Write output in binary. Default is to write in hex. #[structopt(short, long)] pub raw: bool, /// The name of the chain for that the genesis state should be exported. - #[structopt(long, conflicts_with = "parachain-id")] + #[structopt(long)] pub chain: Option, } @@ -90,9 +87,9 @@ pub struct Cli { #[structopt(flatten)] pub run: cumulus_client_cli::RunCmd, - /// Relaychain arguments + /// Relay chain arguments #[structopt(raw = true)] - pub relaychain_args: Vec, + pub relay_chain_args: Vec, } #[derive(Debug)] diff --git a/parachain-template/node/src/command.rs b/parachain-template/node/src/command.rs index e09fee29d9..925815cf14 100644 --- a/parachain-template/node/src/command.rs +++ b/parachain-template/node/src/command.rs @@ -13,19 +13,19 @@ use sc_cli::{ ChainSpec, CliConfiguration, DefaultConfigurationValues, ImportParams, KeystoreParams, NetworkParams, Result, RuntimeVersion, SharedParams, SubstrateCli, }; -use sc_service::config::{BasePath, PrometheusConfig}; +use sc_service::{ + config::{BasePath, PrometheusConfig}, + TaskManager, +}; use sp_core::hexdisplay::HexDisplay; use sp_runtime::traits::Block as BlockT; use std::{io::Write, net::SocketAddr}; -fn load_spec( - id: &str, - para_id: ParaId, -) -> std::result::Result, String> { +fn load_spec(id: &str) -> std::result::Result, String> { Ok(match id { - "dev" => Box::new(chain_spec::development_config(para_id)), - "template-rococo" => Box::new(chain_spec::local_testnet_config(para_id)), - "" | "local" => Box::new(chain_spec::local_testnet_config(para_id)), + "dev" => Box::new(chain_spec::development_config()), + "template-rococo" => Box::new(chain_spec::local_testnet_config()), + "" | "local" => Box::new(chain_spec::local_testnet_config()), path => Box::new(chain_spec::ChainSpec::from_json_file(std::path::PathBuf::from(path))?), }) } @@ -40,13 +40,11 @@ impl SubstrateCli for Cli { } fn description() -> String { - format!( - "Parachain Collator Template\n\nThe command-line arguments provided first will be \ + "Parachain Collator Template\n\nThe command-line arguments provided first will be \ passed to the parachain node, while the arguments provided after -- will be passed \ - to the relaychain node.\n\n\ - {} [parachain-args] -- [relaychain-args]", - Self::executable_name() - ) + to the relay chain node.\n\n\ + parachain-collator -- " + .into() } fn author() -> String { @@ -62,7 +60,7 @@ impl SubstrateCli for Cli { } fn load_spec(&self, id: &str) -> std::result::Result, String> { - load_spec(id, self.run.parachain_id.unwrap_or(2000).into()) + load_spec(id) } fn native_runtime_version(_: &Box) -> &'static RuntimeVersion { @@ -82,8 +80,8 @@ impl SubstrateCli for RelayChainCli { fn description() -> String { "Parachain Collator Template\n\nThe command-line arguments provided first will be \ passed to the parachain node, while the arguments provided after -- will be passed \ - to the relaychain node.\n\n\ - parachain-collator [parachain-args] -- [relaychain-args]" + to the relay chain node.\n\n\ + parachain-collator -- " .into() } @@ -171,7 +169,7 @@ pub fn run() -> Result<()> { runner.sync_run(|config| { let polkadot_cli = RelayChainCli::new( &config, - [RelayChainCli::executable_name()].iter().chain(cli.relaychain_args.iter()), + [RelayChainCli::executable_name()].iter().chain(cli.relay_chain_args.iter()), ); let polkadot_config = SubstrateCli::create_configuration( @@ -194,10 +192,9 @@ pub fn run() -> Result<()> { builder.with_profiling(sc_tracing::TracingReceiver::Log, ""); let _ = builder.init(); - let block: Block = generate_genesis_block(&load_spec( - ¶ms.chain.clone().unwrap_or_default(), - params.parachain_id.unwrap_or(2000).into(), - )?)?; + let spec = load_spec(¶ms.chain.clone().unwrap_or_default())?; + let state_version = Cli::native_runtime_version(&spec).state_version(); + let block: Block = generate_genesis_block(&spec, state_version)?; let raw_header = block.header().encode(); let output_buf = if params.raw { raw_header @@ -244,25 +241,44 @@ pub fn run() -> Result<()> { You can enable it with `--features runtime-benchmarks`." .into()) }, + Some(Subcommand::TryRuntime(cmd)) => + if cfg!(feature = "try-runtime") { + let runner = cli.create_runner(cmd)?; + + // grab the task manager. + let registry = &runner.config().prometheus_config.as_ref().map(|cfg| &cfg.registry); + let task_manager = + TaskManager::new(runner.config().tokio_handle.clone(), *registry) + .map_err(|e| format!("Error: {:?}", e))?; + + runner.async_run(|config| { + Ok((cmd.run::(config), task_manager)) + }) + } else { + Err("Try-runtime must be enabled by `--features try-runtime`.".into()) + }, None => { let runner = cli.create_runner(&cli.run.normalize())?; runner.run_node_until_exit(|config| async move { - let para_id = - chain_spec::Extensions::try_get(&*config.chain_spec).map(|e| e.para_id); + let para_id = chain_spec::Extensions::try_get(&*config.chain_spec) + .map(|e| e.para_id) + .ok_or_else(|| "Could not find parachain ID in chain-spec.")?; let polkadot_cli = RelayChainCli::new( &config, - [RelayChainCli::executable_name()].iter().chain(cli.relaychain_args.iter()), + [RelayChainCli::executable_name()].iter().chain(cli.relay_chain_args.iter()), ); - let id = ParaId::from(cli.run.parachain_id.or(para_id).unwrap_or(2000)); + let id = ParaId::from(para_id); let parachain_account = AccountIdConversion::::into_account(&id); - let block: Block = - generate_genesis_block(&config.chain_spec).map_err(|e| format!("{:?}", e))?; + let state_version = + RelayChainCli::native_runtime_version(&config.chain_spec).state_version(); + let block: Block = generate_genesis_block(&config.chain_spec, state_version) + .map_err(|e| format!("{:?}", e))?; let genesis_state = format!("0x{:?}", HexDisplay::from(&block.header().encode())); let tokio_handle = config.tokio_handle.clone(); @@ -338,11 +354,24 @@ impl CliConfiguration for RelayChainCli { self.base.base.rpc_ws(default_listen_port) } - fn prometheus_config(&self, default_listen_port: u16) -> Result> { - self.base.base.prometheus_config(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) -> Result<()> { + 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"); } diff --git a/parachain-template/node/src/main.rs b/parachain-template/node/src/main.rs index 99dc7849cf..ba9f28b354 100644 --- a/parachain-template/node/src/main.rs +++ b/parachain-template/node/src/main.rs @@ -1,4 +1,4 @@ -//! Substrate Node CLI library. +//! Substrate Parachain Node Template CLI #![warn(missing_docs)] diff --git a/parachain-template/node/src/service.rs b/parachain-template/node/src/service.rs index ff11038ad0..3d87547ded 100644 --- a/parachain-template/node/src/service.rs +++ b/parachain-template/node/src/service.rs @@ -1,7 +1,7 @@ //! Service and ServiceFactory implementation. Specialized wrapper over substrate service. // std -use std::sync::Arc; +use std::{sync::Arc, time::Duration}; // Local Runtime Types use parachain_template_runtime::{ @@ -9,15 +9,15 @@ use parachain_template_runtime::{ }; // Cumulus Imports -use cumulus_client_consensus_aura::{ - build_aura_consensus, BuildAuraConsensusParams, SlotProportion, -}; +use cumulus_client_consensus_aura::{AuraConsensus, BuildAuraConsensusParams, SlotProportion}; use cumulus_client_consensus_common::ParachainConsensus; -use cumulus_client_network::build_block_announce_validator; +use cumulus_client_network::BlockAnnounceValidator; use cumulus_client_service::{ prepare_node_config, start_collator, start_full_node, StartCollatorParams, StartFullNodeParams, }; use cumulus_primitives_core::ParaId; +use cumulus_relay_chain_interface::RelayChainInterface; +use cumulus_relay_chain_local::build_relay_chain_interface; // Substrate Imports use sc_client_api::ExecutorProvider; @@ -114,6 +114,7 @@ where config.wasm_method, config.default_heap_pages, config.max_runtime_instances, + config.runtime_cache_size, ); let (client, backend, keystore_container, task_manager) = @@ -127,7 +128,7 @@ where let telemetry_worker_handle = telemetry.as_ref().map(|(worker, _)| worker.handle()); let telemetry = telemetry.map(|(worker, telemetry)| { - task_manager.spawn_handle().spawn("telemetry", worker.run()); + task_manager.spawn_handle().spawn("telemetry", None, worker.run()); telemetry }); @@ -215,7 +216,7 @@ where Option<&Registry>, Option, &TaskManager, - &polkadot_service::NewFull, + Arc, Arc< sc_transaction_pool::FullPool< Block, @@ -236,27 +237,23 @@ where let params = new_partial::(¶chain_config, build_import_queue)?; let (mut telemetry, telemetry_worker_handle) = params.other; - let relay_chain_full_node = - cumulus_client_service::build_polkadot_full_node(polkadot_config, telemetry_worker_handle) + 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, telemetry_worker_handle, &mut task_manager) .map_err(|e| match e { polkadot_service::Error::Sub(x) => x, s => format!("{}", s).into(), })?; - let client = params.client.clone(); - let backend = params.backend.clone(); - let block_announce_validator = build_block_announce_validator( - relay_chain_full_node.client.clone(), - id, - Box::new(relay_chain_full_node.network.clone()), - relay_chain_full_node.backend.clone(), - ); + let block_announce_validator = BlockAnnounceValidator::new(relay_chain_interface.clone(), id); let force_authoring = parachain_config.force_authoring; let validator = parachain_config.role.is_authority(); let prometheus_registry = parachain_config.prometheus_registry().cloned(); let transaction_pool = params.transaction_pool.clone(); - let mut task_manager = params.task_manager; let import_queue = cumulus_client_service::SharedImportQueue::new(params.import_queue); let (network, system_rpc_tx, start_network) = sc_service::build_network(sc_service::BuildNetworkParams { @@ -265,8 +262,9 @@ where transaction_pool: transaction_pool.clone(), spawn_handle: task_manager.spawn_handle(), import_queue: import_queue.clone(), - on_demand: None, - block_announce_validator_builder: Some(Box::new(|_| block_announce_validator)), + block_announce_validator_builder: Some(Box::new(|_| { + Box::new(block_announce_validator) + })), warp_sync: None, })?; @@ -286,8 +284,6 @@ where }; sc_service::spawn_tasks(sc_service::SpawnTasksParams { - on_demand: None, - remote_blockchain: None, rpc_extensions_builder, client: client.clone(), transaction_pool: transaction_pool.clone(), @@ -311,7 +307,7 @@ where prometheus_registry.as_ref(), telemetry.as_ref().map(|t| t.handle()), &task_manager, - &relay_chain_full_node, + relay_chain_interface.clone(), transaction_pool, network, params.keystore_container.sync_keystore(), @@ -326,10 +322,12 @@ where announce_block, client: client.clone(), task_manager: &mut task_manager, - relay_chain_full_node, + relay_chain_interface, spawner, parachain_consensus, import_queue, + collator_key, + slot_duration: Duration::from_secs(6), }; start_collator(params).await?; @@ -339,7 +337,7 @@ where announce_block, task_manager: &mut task_manager, para_id: id, - relay_chain_full_node, + relay_chain_interface, }; start_full_node(params)?; @@ -415,7 +413,7 @@ pub async fn start_parachain_node( prometheus_registry, telemetry, task_manager, - relay_chain_node, + relay_chain_interface, transaction_pool, sync_oracle, keystore, @@ -430,62 +428,48 @@ pub async fn start_parachain_node( telemetry.clone(), ); - let relay_chain_backend = relay_chain_node.backend.clone(); - let relay_chain_client = relay_chain_node.client.clone(); - Ok(build_aura_consensus::< - sp_consensus_aura::sr25519::AuthorityPair, - _, - _, - _, - _, - _, - _, - _, - _, - _, - >(BuildAuraConsensusParams { - proposer_factory, - create_inherent_data_providers: move |_, (relay_parent, validation_data)| { - let parachain_inherent = - cumulus_primitives_parachain_inherent::ParachainInherentData::create_at_with_client( - relay_parent, - &relay_chain_client, - &*relay_chain_backend, - &validation_data, - id, - ); - async move { - let time = sp_timestamp::InherentDataProvider::from_system_time(); + Ok(AuraConsensus::build::( + BuildAuraConsensusParams { + proposer_factory, + create_inherent_data_providers: move |_, (relay_parent, validation_data)| { + let parachain_inherent = + cumulus_primitives_parachain_inherent::ParachainInherentData::create_at( + relay_parent, + &relay_chain_interface, + &validation_data, + id, + ); + async move { + let time = sp_timestamp::InherentDataProvider::from_system_time(); - let slot = + let slot = sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_duration( *time, slot_duration.slot_duration(), ); - let parachain_inherent = parachain_inherent.ok_or_else(|| { - Box::::from( - "Failed to create parachain inherent", - ) - })?; - Ok((time, slot, parachain_inherent)) - } + let parachain_inherent = parachain_inherent.ok_or_else(|| { + Box::::from( + "Failed to create parachain inherent", + ) + })?; + Ok((time, slot, parachain_inherent)) + } + }, + block_import: client.clone(), + para_client: client, + backoff_authoring_blocks: Option::<()>::None, + sync_oracle, + keystore, + force_authoring, + slot_duration, + // We got around 500ms for proposing + block_proposal_slot_portion: SlotProportion::new(1f32 / 24f32), + // And a maximum of 750ms if slots are skipped + max_block_proposal_slot_portion: Some(SlotProportion::new(1f32 / 16f32)), + telemetry, }, - block_import: client.clone(), - relay_chain_client: relay_chain_node.client.clone(), - relay_chain_backend: relay_chain_node.backend.clone(), - para_client: client, - backoff_authoring_blocks: Option::<()>::None, - sync_oracle, - keystore, - force_authoring, - slot_duration, - // We got around 500ms for proposing - block_proposal_slot_portion: SlotProportion::new(1f32 / 24f32), - // And a maximum of 750ms if slots are skipped - max_block_proposal_slot_portion: Some(SlotProportion::new(1f32 / 16f32)), - telemetry, - })) + )) }, ) .await diff --git a/parachain-template/pallets/template/Cargo.toml b/parachain-template/pallets/template/Cargo.toml index ccde37831a..ce58e0dcdb 100644 --- a/parachain-template/pallets/template/Cargo.toml +++ b/parachain-template/pallets/template/Cargo.toml @@ -6,7 +6,7 @@ version = "0.1.0" license = "Unlicense" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" -edition = "2018" +edition = "2021" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] @@ -15,19 +15,19 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.0.0", features = ["derive"], default-features = false } scale-info = { version = "1.0.0", default-features = false, features = ["derive"] } -frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true } -frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } -frame-system = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +frame-benchmarking = { git = "https://github.com/paritytech/substrate", default-features = false, optional = true , branch = "master" } +frame-support = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } +frame-system = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } [dev-dependencies] -serde = { version = "1.0.119" } -sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } -sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } -sp-io = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +serde = { version = "1.0.132" } +sp-core = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } +sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } +sp-io = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } [features] default = ["std"] -runtime-benchmarks = ["frame-benchmarking"] +runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"] std = [ "codec/std", "scale-info/std", @@ -35,3 +35,4 @@ std = [ "frame-system/std", "frame-benchmarking/std", ] +try-runtime = [ "frame-support/try-runtime" ] diff --git a/parachain-template/pallets/template/src/benchmarking.rs b/parachain-template/pallets/template/src/benchmarking.rs index 4e1acc8bef..fea9e65969 100644 --- a/parachain-template/pallets/template/src/benchmarking.rs +++ b/parachain-template/pallets/template/src/benchmarking.rs @@ -3,7 +3,7 @@ use super::*; #[allow(unused)] -use crate::Module as Template; +use crate::Pallet as Template; use frame_benchmarking::{benchmarks, impl_benchmark_test_suite, whitelisted_caller}; use frame_system::RawOrigin; diff --git a/parachain-template/pallets/template/src/mock.rs b/parachain-template/pallets/template/src/mock.rs index 525375e2d8..917356c1d9 100644 --- a/parachain-template/pallets/template/src/mock.rs +++ b/parachain-template/pallets/template/src/mock.rs @@ -51,6 +51,7 @@ impl system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = SS58Prefix; type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl pallet_template::Config for Test { diff --git a/parachain-template/runtime/Cargo.toml b/parachain-template/runtime/Cargo.toml index e3da6f807b..a432fa95c5 100644 --- a/parachain-template/runtime/Cargo.toml +++ b/parachain-template/runtime/Cargo.toml @@ -6,7 +6,7 @@ description = "A new Cumulus FRAME-based Substrate Runtime, ready for hacking to license = "Unlicense" homepage = "https://substrate.io" repository = "https://github.com/paritytech/cumulus/" -edition = "2018" +edition = "2021" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] @@ -15,10 +15,11 @@ targets = ["x86_64-unknown-linux-gnu"] substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", branch = "master" } [dependencies] +hex-literal = { version = "0.3.1", optional = true } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"]} log = { version = "0.4.14", default-features = false } scale-info = { version = "1.0.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.119", optional = true, features = ["derive"] } +serde = { version = "1.0.132", optional = true, features = ["derive"] } smallvec = "1.6.1" # Local Dependencies @@ -41,6 +42,7 @@ sp-version = { git = "https://github.com/paritytech/substrate", default-features ## Substrate FRAME Dependencies frame-benchmarking = { git = "https://github.com/paritytech/substrate", default-features = false, optional = true , branch = "master" } +frame-try-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, optional = true , branch = "master" } frame-executive = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } frame-system = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } @@ -51,7 +53,6 @@ frame-system-rpc-runtime-api = { git = "https://github.com/paritytech/substrate" pallet-aura = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } pallet-authorship = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } pallet-balances = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } -pallet-randomness-collective-flip = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } pallet-session = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } pallet-sudo = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } pallet-timestamp = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } @@ -69,6 +70,7 @@ cumulus-primitives-timestamp = { path = "../../primitives/timestamp", default-fe cumulus-primitives-utility = { path = "../../primitives/utility", default-features = false } pallet-collator-selection = { path = "../../pallets/collator-selection", default-features = false } parachain-info = { path = "../../polkadot-parachains/pallets/parachain-info", default-features = false } +cumulus-pallet-session-benchmarking = {path = "../../pallets/session-benchmarking", default-features = false, version = "3.0.0"} # Polkadot Dependencies pallet-xcm = { git = "https://github.com/paritytech/polkadot", default-features = false , branch = "master" } @@ -106,7 +108,6 @@ std = [ "pallet-authorship/std", "pallet-balances/std", "pallet-collator-selection/std", - "pallet-randomness-collective-flip/std", "pallet-session/std", "pallet-sudo/std", "pallet-template/std", @@ -130,9 +131,10 @@ std = [ ] runtime-benchmarks = [ + "hex-literal", "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", - "frame-benchmarking", + "frame-benchmarking/runtime-benchmarks", "frame-system-benchmarking", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", @@ -141,4 +143,10 @@ runtime-benchmarks = [ "pallet-template/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", + "cumulus-pallet-session-benchmarking/runtime-benchmarks", +] + +try-runtime = [ + "frame-try-runtime", + "frame-executive/try-runtime", ] diff --git a/parachain-template/runtime/src/lib.rs b/parachain-template/runtime/src/lib.rs index bcdefa48f9..fbd02847ae 100644 --- a/parachain-template/runtime/src/lib.rs +++ b/parachain-template/runtime/src/lib.rs @@ -23,7 +23,7 @@ use sp_version::RuntimeVersion; use frame_support::{ construct_runtime, match_type, parameter_types, - traits::Everything, + traits::{Everything, Nothing}, weights::{ constants::{BlockExecutionWeight, ExtrinsicBaseWeight, WEIGHT_PER_SECOND}, DispatchClass, IdentityFee, Weight, WeightToFeeCoefficient, WeightToFeeCoefficients, @@ -33,7 +33,7 @@ use frame_support::{ }; use frame_system::{ limits::{BlockLength, BlockWeights}, - EnsureOneOf, EnsureRoot, + EnsureRoot, }; pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; pub use sp_runtime::{MultiAddress, Perbill, Permill}; @@ -42,7 +42,7 @@ pub use sp_runtime::{MultiAddress, Perbill, Permill}; pub use sp_runtime::BuildStorage; // Polkadot Imports -use pallet_xcm::{EnsureXcm, IsMajorityOfBody, XcmPassthrough}; +use pallet_xcm::XcmPassthrough; use polkadot_parachain::primitives::Sibling; use polkadot_runtime_common::{BlockHashCount, RocksDbWeight, SlowAdjustingFeeUpdate}; @@ -50,10 +50,10 @@ use polkadot_runtime_common::{BlockHashCount, RocksDbWeight, SlowAdjustingFeeUpd use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, CurrencyAdapter, - EnsureXcmOrigin, FixedWeightBounds, IsConcrete, LocationInverter, NativeAsset, - ParentAsSuperuser, ParentIsDefault, RelayChainAsNative, SiblingParachainAsNative, - SiblingParachainConvertsVia, SignedAccountId32AsNative, SovereignSignedViaLocation, - TakeWeightCredit, UsingComponents, + EnsureXcmOrigin, FixedWeightBounds, IsConcrete, LocationInverter, NativeAsset, ParentIsDefault, + RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, + SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, + UsingComponents, }; use xcm_executor::{Config, XcmExecutor}; @@ -96,6 +96,7 @@ pub type BlockId = generic::BlockId; /// The SignedExtension to the basic transaction logic. pub type SignedExtra = ( + frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, frame_system::CheckGenesis, @@ -117,19 +118,9 @@ pub type Executive = frame_executive::Executive< Block, frame_system::ChainContext, Runtime, - AllPallets, - OnRuntimeUpgrade, + AllPalletsWithSystem, >; -pub struct OnRuntimeUpgrade; -impl frame_support::traits::OnRuntimeUpgrade for OnRuntimeUpgrade { - fn on_runtime_upgrade() -> u64 { - frame_support::migrations::migrate_from_pallet_version_to_storage_version::< - AllPalletsWithSystem, - >(&RocksDbWeight::get()) - } -} - /// Handles converting a weight scalar to a fee value, based on the scale and granularity of the /// node's balance type. /// @@ -189,6 +180,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, + state_version: 1, }; /// This determines the average expected block time that we are targeting. @@ -213,12 +205,9 @@ pub const UNIT: Balance = 1_000_000_000_000; pub const MILLIUNIT: Balance = 1_000_000_000; pub const MICROUNIT: Balance = 1_000_000; -/// The existential deposit. Set to 1/10 of the Rococo Relay Chain. +/// The existential deposit. Set to 1/10 of the Connected Relay Chain. pub const EXISTENTIAL_DEPOSIT: Balance = MILLIUNIT; -// 1 in 4 blocks (on average, not counting collisions) will be primary babe blocks. -pub const PRIMARY_PROBABILITY: (u64, u64) = (1, 4); - /// We assume that ~5% 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(5); @@ -315,6 +304,7 @@ impl frame_system::Config for Runtime { type SS58Prefix = SS58Prefix; /// The action to take on a Runtime Upgrade type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { @@ -390,14 +380,12 @@ impl cumulus_pallet_parachain_system::Config for Runtime { type ReservedXcmpWeight = ReservedXcmpWeight; } -impl pallet_randomness_collective_flip::Config for Runtime {} - impl parachain_info::Config for Runtime {} impl cumulus_pallet_aura_ext::Config for Runtime {} parameter_types! { - pub const RocLocation: MultiLocation = MultiLocation::parent(); + pub const RelayLocation: MultiLocation = MultiLocation::parent(); pub const RelayNetwork: NetworkId = NetworkId::Any; pub RelayChainOrigin: Origin = cumulus_pallet_xcm::Origin::Relay.into(); pub Ancestry: MultiLocation = Parachain(ParachainInfo::parachain_id().into()).into(); @@ -420,7 +408,7 @@ pub type LocalAssetTransactor = CurrencyAdapter< // Use this currency: Balances, // Use this currency when it is a fungible asset matching the given location or name: - IsConcrete, + IsConcrete, // Do a simple punn to convert an AccountId32 MultiLocation into a native chain account ID: LocationToAccountId, // Our chain's account ID type (we can't get away without mentioning it explicitly): @@ -438,14 +426,11 @@ pub type XcmOriginToTransactDispatchOrigin = ( // foreign chains who want to have a local sovereign account on this chain which they control. SovereignSignedViaLocation, // Native converter for Relay-chain (Parent) location; will converts to a `Relay` origin when - // recognised. + // recognized. RelayChainAsNative, // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when - // recognised. + // recognized. SiblingParachainAsNative, - // Superuser converter for the Relay-chain (Parent) location. This will allow it to issue a - // transaction from the Root origin. - ParentAsSuperuser, // Native signed account converter; this just converts an `AccountId32` origin into a normal // `Origin::Signed` origin of the same 32-byte value. SignedAccountId32AsNative, @@ -482,11 +467,11 @@ impl Config for XcmConfig { type AssetTransactor = LocalAssetTransactor; type OriginConverter = XcmOriginToTransactDispatchOrigin; type IsReserve = NativeAsset; - type IsTeleporter = NativeAsset; // Should be enough to allow teleportation of ROC + type IsTeleporter = (); // Teleporting is disabled. type LocationInverter = LocationInverter; type Barrier = Barrier; type Weigher = FixedWeightBounds; - type Trader = UsingComponents, RocLocation, AccountId, Balances, ()>; + type Trader = UsingComponents, RelayLocation, AccountId, Balances, ()>; type ResponseHandler = PolkadotXcm; type AssetTrap = PolkadotXcm; type AssetClaims = PolkadotXcm; @@ -500,7 +485,7 @@ parameter_types! { } /// No local origins on this chain are allowed to dispatch XCM sends/executions. -pub type LocalOriginToLocation = (); +pub type LocalOriginToLocation = SignedToAccountId32; /// The means for routing XCM messages which are not for local execution into the right message /// queues. @@ -516,16 +501,19 @@ impl pallet_xcm::Config for Runtime { type SendXcmOrigin = EnsureXcmOrigin; type XcmRouter = XcmRouter; type ExecuteXcmOrigin = EnsureXcmOrigin; - type XcmExecuteFilter = Everything; + type XcmExecuteFilter = Nothing; + // ^ Disable dispatchable execute on the XCM pallet. + // Needs to be `Everything` for local testing. type XcmExecutor = XcmExecutor; type XcmTeleportFilter = Everything; - type XcmReserveTransferFilter = Everything; + type XcmReserveTransferFilter = Nothing; type Weigher = FixedWeightBounds; type LocationInverter = LocationInverter; type Origin = Origin; type Call = Call; const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; + // ^ Override for AdvertisedXcmVersion default type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; } @@ -539,6 +527,7 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime { type XcmExecutor = XcmExecutor; type ChannelInfo = ParachainSystem; type VersionWrapper = (); + type ExecuteOverweightOrigin = EnsureRoot; } impl cumulus_pallet_dmp_queue::Config for Runtime { @@ -582,12 +571,8 @@ parameter_types! { pub const ExecutiveBody: BodyId = BodyId::Executive; } -// We allow root and the Relay Chain council to execute privileged collator selection operations. -pub type CollatorSelectionUpdateOrigin = EnsureOneOf< - AccountId, - EnsureRoot, - EnsureXcm>, ->; +// We allow root only to execute privileged collator selection operations. +pub type CollatorSelectionUpdateOrigin = EnsureRoot; impl pallet_collator_selection::Config for Runtime { type Event = Event; @@ -622,9 +607,8 @@ construct_runtime!( ParachainSystem: cumulus_pallet_parachain_system::{ Pallet, Call, Config, Storage, Inherent, Event, ValidateUnsigned, } = 1, - RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Pallet, Storage} = 2, - Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent} = 3, - ParachainInfo: parachain_info::{Pallet, Storage, Config} = 4, + Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent} = 2, + ParachainInfo: parachain_info::{Pallet, Storage, Config} = 3, // Monetary stuff. Balances: pallet_balances::{Pallet, Call, Storage, Config, Event} = 10, @@ -755,6 +739,18 @@ impl_runtime_apis! { } } + #[cfg(feature = "try-runtime")] + impl frame_try_runtime::TryRuntime for Runtime { + fn on_runtime_upgrade() -> (Weight, Weight) { + log::info!("try-runtime::on_runtime_upgrade parachain-template."); + let weight = Executive::try_runtime_upgrade().unwrap(); + (weight, RuntimeBlockWeights::get().max_block) + } + + fn execute_block_no_check(block: Block) -> Weight { + Executive::execute_block_no_check(block) + } + } #[cfg(feature = "runtime-benchmarks")] impl frame_benchmarking::Benchmark for Runtime { @@ -771,6 +767,7 @@ impl_runtime_apis! { list_benchmark!(list, extra, frame_system, SystemBench::); list_benchmark!(list, extra, pallet_balances, Balances); + list_benchmark!(list, extra, pallet_session, SessionBench::); list_benchmark!(list, extra, pallet_timestamp, Timestamp); list_benchmark!(list, extra, pallet_collator_selection, CollatorSelection); diff --git a/polkadot-parachains/Cargo.toml b/polkadot-parachains/Cargo.toml index 3e0a82b754..c124283a41 100644 --- a/polkadot-parachains/Cargo.toml +++ b/polkadot-parachains/Cargo.toml @@ -1,9 +1,9 @@ [package] name = "polkadot-collator" -version = "4.0.0" +version = "5.0.0" authors = ["Parity Technologies "] build = "build.rs" -edition = "2018" +edition = "2021" [[bin]] name = "polkadot-collator" @@ -14,21 +14,22 @@ futures = { version = "0.3.1", features = ["compat"] } log = "0.4.8" codec = { package = "parity-scale-codec", version = "2.3.0" } structopt = "0.3.3" -serde = { version = "1.0.101", features = ["derive"] } +serde = { version = "1.0.132", features = ["derive"] } hex-literal = "0.2.1" async-trait = "0.1.42" # Parachain runtimes -rococo-parachain-runtime = { package = "rococo-runtime", path = "rococo" } +rococo-parachain-runtime = { path = "rococo-parachain" } shell-runtime = { path = "shell" } +seedling-runtime = { path = "seedling" } statemint-runtime = { path = "statemint" } statemine-runtime = { path = "statemine" } westmint-runtime = { path = "westmint" } parachains-common = { path = "parachains-common" } # Substrate dependencies -frame-benchmarking = { git = 'https://github.com/paritytech/substrate', branch = "master" } -frame-benchmarking-cli = { git = 'https://github.com/paritytech/substrate', branch = "master" } +frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master" } +frame-benchmarking-cli = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } sp-io = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } @@ -57,6 +58,9 @@ sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-consensus-aura = { git = "https://github.com/paritytech/substrate", branch = "master" } substrate-prometheus-endpoint = { git = "https://github.com/paritytech/substrate", branch = "master" } +# try-runtime stuff. +try-runtime-cli = { git = "https://github.com/paritytech/substrate", branch = "master" } + # RPC related dependencies jsonrpc-core = "18.0.0" sc-transaction-pool-api = { git = "https://github.com/paritytech/substrate", branch = "master" } @@ -72,6 +76,8 @@ cumulus-client-service = { path = "../client/service" } cumulus-client-network = { path = "../client/network" } cumulus-primitives-core = { path = "../primitives/core" } cumulus-primitives-parachain-inherent = { path = "../primitives/parachain-inherent" } +cumulus-relay-chain-interface = { path = "../client/relay-chain-interface" } +cumulus-relay-chain-local = { path = "../client/relay-chain-local" } # Polkadot dependencies polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "master" } @@ -90,8 +96,14 @@ tempfile = "3.2.0" [features] default = [] runtime-benchmarks = [ - 'polkadot-service/runtime-benchmarks', - 'statemint-runtime/runtime-benchmarks', - 'statemine-runtime/runtime-benchmarks', - 'westmint-runtime/runtime-benchmarks', + "polkadot-service/runtime-benchmarks", + "statemint-runtime/runtime-benchmarks", + "statemine-runtime/runtime-benchmarks", + "westmint-runtime/runtime-benchmarks", +] +try-runtime = [ + 'statemint-runtime/try-runtime', + 'statemine-runtime/try-runtime', + 'westmint-runtime/try-runtime', + 'shell-runtime/try-runtime', ] diff --git a/polkadot-parachains/pallets/parachain-info/Cargo.toml b/polkadot-parachains/pallets/parachain-info/Cargo.toml index c5add537a0..2ddec4de78 100644 --- a/polkadot-parachains/pallets/parachain-info/Cargo.toml +++ b/polkadot-parachains/pallets/parachain-info/Cargo.toml @@ -1,13 +1,13 @@ [package] authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" name = "parachain-info" version = "0.1.0" [dependencies] codec = { package = "parity-scale-codec", version = "2.3.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.101", optional = true, features = ["derive"] } +serde = { version = "1.0.132", optional = true, features = ["derive"] } frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } frame-system = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } diff --git a/polkadot-parachains/pallets/ping/Cargo.toml b/polkadot-parachains/pallets/ping/Cargo.toml index 28b08451ab..e813d692b4 100644 --- a/polkadot-parachains/pallets/ping/Cargo.toml +++ b/polkadot-parachains/pallets/ping/Cargo.toml @@ -1,13 +1,13 @@ [package] authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" name = "cumulus-ping" version = "0.1.0" [dependencies] codec = { package = "parity-scale-codec", version = "2.3.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.101", optional = true, features = ["derive"] } +serde = { version = "1.0.132", optional = true, features = ["derive"] } sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } diff --git a/polkadot-parachains/parachains-common/Cargo.toml b/polkadot-parachains/parachains-common/Cargo.toml index 0a4c4127cd..6099b2036c 100644 --- a/polkadot-parachains/parachains-common/Cargo.toml +++ b/polkadot-parachains/parachains-common/Cargo.toml @@ -2,63 +2,63 @@ name = "parachains-common" version = "1.0.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" description = "Logic which is common to all parachain runtimes" [package.metadata.docs.rs] -targets = ['x86_64-unknown-linux-gnu'] +targets = ["x86_64-unknown-linux-gnu"] [dependencies] # External dependencies -codec = { package = 'parity-scale-codec', version = '2.3.0', features = ['derive'], default-features = false } +codec = { package = "parity-scale-codec", version = "2.3.0", features = ["derive"], default-features = false } scale-info = { version = "1.0.0", default-features = false, features = ["derive"] } # Substrate dependencies -sp-consensus-aura = { git = 'https://github.com/paritytech/substrate', branch = "master", default-features = false } -sp-std = { git = 'https://github.com/paritytech/substrate', branch = "master", default-features = false } -sp-io = { git = 'https://github.com/paritytech/substrate', branch = "master", default-features = false } -frame-executive = { git = 'https://github.com/paritytech/substrate', branch = "master", default-features = false } -frame-support = { git = 'https://github.com/paritytech/substrate', branch = "master", default-features = false } -frame-system = { git = 'https://github.com/paritytech/substrate', branch = "master", default-features = false } -pallet-assets = { git = 'https://github.com/paritytech/substrate', branch = "master", default-features = false } -pallet-authorship = { git = 'https://github.com/paritytech/substrate', branch = "master", default-features = false } -pallet-balances = { git = 'https://github.com/paritytech/substrate', branch = "master", default-features = false } -sp-runtime = { git = 'https://github.com/paritytech/substrate', branch = "master", default-features = false } -sp-core = { git = 'https://github.com/paritytech/substrate', branch = "master", default-features = false } +sp-consensus-aura = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-io = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +frame-executive = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +frame-system = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +pallet-asset-tx-payment = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +pallet-assets = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +pallet-authorship = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } # Polkadot dependencies -polkadot-runtime-common = { git = 'https://github.com/paritytech/polkadot', branch = "master", default-features = false } -polkadot-primitives = { git = 'https://github.com/paritytech/polkadot', branch = "master", default-features = false } -xcm = { git = 'https://github.com/paritytech/polkadot', branch = "master", default-features = false } -xcm-executor = { git = 'https://github.com/paritytech/polkadot', branch = "master", default-features = false } +polkadot-runtime-common = { git = "https://github.com/paritytech/polkadot", default-features = false , branch = "master" } +polkadot-primitives = { git = "https://github.com/paritytech/polkadot", default-features = false , branch = "master" } +xcm = { git = "https://github.com/paritytech/polkadot", default-features = false , branch = "master" } +xcm-executor = { git = "https://github.com/paritytech/polkadot", default-features = false , branch = "master" } # Local dependencies -pallet-asset-tx-payment = { path = '../../pallets/asset-tx-payment', default-features = false } -pallet-collator-selection = { path = '../../pallets/collator-selection', default-features = false } +pallet-collator-selection = { path = "../../pallets/collator-selection", default-features = false } [dev-dependencies] -sp-io = { git = 'https://github.com/paritytech/substrate', branch = "master", default-features = false } -pallet-authorship = { git = 'https://github.com/paritytech/substrate', branch = "master", default-features = false } +sp-io = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } +pallet-authorship = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } [build-dependencies] -substrate-wasm-builder = { git = 'https://github.com/paritytech/substrate', branch = "master" } +substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", branch = "master" } [features] default = ["std"] std = [ - 'codec/std', - 'scale-info/std', - 'sp-consensus-aura/std', - 'sp-std/std', - 'sp-io/std', - 'frame-support/std', - 'frame-executive/std', - 'frame-system/std', - 'pallet-asset-tx-payment/std', - 'pallet-collator-selection/std', - 'pallet-assets/std', - 'pallet-authorship/std', - 'pallet-balances/std', - 'polkadot-runtime-common/std', - 'polkadot-primitives/std', + "codec/std", + "scale-info/std", + "sp-consensus-aura/std", + "sp-std/std", + "sp-io/std", + "frame-support/std", + "frame-executive/std", + "frame-system/std", + "pallet-asset-tx-payment/std", + "pallet-collator-selection/std", + "pallet-assets/std", + "pallet-authorship/std", + "pallet-balances/std", + "polkadot-runtime-common/std", + "polkadot-primitives/std", ] diff --git a/polkadot-parachains/parachains-common/src/impls.rs b/polkadot-parachains/parachains-common/src/impls.rs index addbc788b1..83e42bedf9 100644 --- a/polkadot-parachains/parachains-common/src/impls.rs +++ b/polkadot-parachains/parachains-common/src/impls.rs @@ -47,10 +47,10 @@ where let numeric_amount = amount.peek(); let staking_pot = >::account_id(); >::resolve_creating(&staking_pot, amount); - >::deposit_event(pallet_balances::Event::Deposit( - staking_pot, - numeric_amount, - )); + >::deposit_event(pallet_balances::Event::Deposit { + who: staking_pot, + amount: numeric_amount, + }); } } @@ -84,9 +84,10 @@ where From + Into, { fn handle_credit(credit: CreditOf, pallet_assets::Pallet>) { - let author = pallet_authorship::Pallet::::author(); - // In case of error: Will drop the result triggering the `OnDrop` of the imbalance. - let _ = pallet_assets::Pallet::::resolve(&author, credit); + if let Some(author) = pallet_authorship::Pallet::::author() { + // In case of error: Will drop the result triggering the `OnDrop` of the imbalance. + let _ = pallet_assets::Pallet::::resolve(&author, credit); + } } } @@ -178,6 +179,7 @@ mod tests { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl pallet_balances::Config for Test { diff --git a/polkadot-parachains/parachains-common/src/lib.rs b/polkadot-parachains/parachains-common/src/lib.rs index 23f90e55e5..f592b94e56 100644 --- a/polkadot-parachains/parachains-common/src/lib.rs +++ b/polkadot-parachains/parachains-common/src/lib.rs @@ -47,7 +47,7 @@ mod types { pub type Hash = sp_core::H256; /// Digest item type. - pub type DigestItem = sp_runtime::generic::DigestItem; + pub type DigestItem = sp_runtime::generic::DigestItem; // Aura consensus authority. pub type AuraId = sp_consensus_aura::sr25519::AuthorityId; diff --git a/polkadot-parachains/res/shell-statemint-head-data b/polkadot-parachains/res/shell-statemint-head-data new file mode 100644 index 0000000000..032a8c73e9 --- /dev/null +++ b/polkadot-parachains/res/shell-statemint-head-data @@ -0,0 +1 @@ +0x000000000000000000000000000000000000000000000000000000000000000000c1ef26b567de07159e4ecd415fbbb0340c56a09c4d72c82516d0f3bc2b782c8003170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c11131400 \ No newline at end of file diff --git a/polkadot-parachains/res/shell-statemint.json b/polkadot-parachains/res/shell-statemint.json new file mode 100644 index 0000000000..a02734316d --- /dev/null +++ b/polkadot-parachains/res/shell-statemint.json @@ -0,0 +1,38 @@ +{ + "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/polkadot-parachains/res/statemine.json b/polkadot-parachains/res/statemine.json index 826cdd37f0..699ff9150d 100644 --- a/polkadot-parachains/res/statemine.json +++ b/polkadot-parachains/res/statemine.json @@ -10,6 +10,7 @@ "telemetryEndpoints": null, "protocolId": null, "properties": { + "ss58Format": 2, "tokenDecimals": 12, "tokenSymbol": "KSM" }, diff --git a/polkadot-parachains/res/statemine_genesis.json b/polkadot-parachains/res/statemine_genesis.json index 95b7a973a4..8b0dee2f8c 100644 --- a/polkadot-parachains/res/statemine_genesis.json +++ b/polkadot-parachains/res/statemine_genesis.json @@ -8,6 +8,7 @@ "telemetryEndpoints": null, "protocolId": null, "properties": { + "ss58Format": 2, "tokenDecimals": 12, "tokenSymbol": "KSM" }, diff --git a/polkadot-parachains/rococo/Cargo.toml b/polkadot-parachains/rococo-parachain/Cargo.toml similarity index 95% rename from polkadot-parachains/rococo/Cargo.toml rename to polkadot-parachains/rococo-parachain/Cargo.toml index 1c4e12ce5f..110c840408 100644 --- a/polkadot-parachains/rococo/Cargo.toml +++ b/polkadot-parachains/rococo-parachain/Cargo.toml @@ -1,8 +1,8 @@ [package] -name = 'rococo-runtime' -version = '0.1.0' +name = "rococo-parachain-runtime" +version = "0.1.0" authors = ["Parity Technologies "] -edition = '2018' +edition = "2021" description = "Simple runtime used by the rococo parachain(s)" [dependencies] @@ -10,7 +10,7 @@ codec = { package = "parity-scale-codec", version = "2.3.0", default-features = log = { version = "0.4.14", default-features = false } parachain-info = { path = "../pallets/parachain-info", default-features = false } scale-info = { version = "1.0.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.101", optional = true, features = ["derive"] } +serde = { version = "1.0.132", optional = true, features = ["derive"] } # Substrate dependencies sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } @@ -32,7 +32,6 @@ frame-system = { git = "https://github.com/paritytech/substrate", default-featur frame-system-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } pallet-assets = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } pallet-balances = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } -pallet-randomness-collective-flip = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } pallet-timestamp = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } pallet-sudo = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } @@ -85,7 +84,6 @@ std = [ "frame-system/std", "pallet-assets/std", "pallet-balances/std", - "pallet-randomness-collective-flip/std", "pallet-timestamp/std", "pallet-sudo/std", "pallet-transaction-payment/std", diff --git a/polkadot-parachains/rococo/build.rs b/polkadot-parachains/rococo-parachain/build.rs similarity index 100% rename from polkadot-parachains/rococo/build.rs rename to polkadot-parachains/rococo-parachain/build.rs diff --git a/polkadot-parachains/rococo/src/lib.rs b/polkadot-parachains/rococo-parachain/src/lib.rs similarity index 93% rename from polkadot-parachains/rococo/src/lib.rs rename to polkadot-parachains/rococo-parachain/src/lib.rs index c45306d4e3..5ad87b3c0f 100644 --- a/polkadot-parachains/rococo/src/lib.rs +++ b/polkadot-parachains/rococo-parachain/src/lib.rs @@ -38,7 +38,7 @@ use sp_version::RuntimeVersion; // A few exports that help ease life for downstream crates. pub use frame_support::{ construct_runtime, match_type, parameter_types, - traits::{Everything, IsInVec, Randomness}, + traits::{EnsureOneOf, Everything, IsInVec, Randomness}, weights::{ constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND}, DispatchClass, IdentityFee, Weight, @@ -47,7 +47,7 @@ pub use frame_support::{ }; use frame_system::{ limits::{BlockLength, BlockWeights}, - EnsureOneOf, EnsureRoot, + EnsureRoot, }; pub use pallet_balances::Call as BalancesCall; pub use pallet_timestamp::Call as TimestampCall; @@ -60,7 +60,10 @@ use parachains_common::{ impls::{AssetsFrom, NonZeroIssuance}, AssetId, }; -use xcm_builder::{AsPrefixedGeneralIndex, ConvertedConcreteAssetId, FungiblesAdapter}; +use xcm_builder::{ + AllowKnownQueryResponses, AllowSubscriptionsFrom, AsPrefixedGeneralIndex, + ConvertedConcreteAssetId, FungiblesAdapter, +}; use xcm_executor::traits::JustTry; // XCM imports @@ -94,6 +97,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, + state_version: 0, }; pub const MILLISECS_PER_BLOCK: u64 = 12000; @@ -185,13 +189,14 @@ impl frame_system::Config for Runtime { type AccountData = pallet_balances::AccountData; type OnNewAccount = (); type OnKilledAccount = (); - type DbWeight = (); + type DbWeight = RocksDbWeight; 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! { @@ -229,8 +234,6 @@ impl pallet_balances::Config for Runtime { type ReserveIdentifier = [u8; 8]; } -impl pallet_randomness_collective_flip::Config for Runtime {} - parameter_types! { pub const OperationalFeeMultiplier: u8 = 5; } @@ -310,7 +313,7 @@ pub type FungiblesTransactor = FungiblesAdapter< ConvertedConcreteAssetId< AssetId, u64, - AsPrefixedGeneralIndex, + AsPrefixedGeneralIndex, JustTry, >, // Convert an XCM MultiLocation into a local account id: @@ -351,8 +354,8 @@ pub type XcmOriginToTransactDispatchOrigin = ( ); parameter_types! { - // One XCM operation is 1_000_000 weight - almost certainly a conservative estimate. - pub UnitWeightCost: Weight = 1_000_000; + // One XCM operation is 1_000_000_000 weight - almost certainly a conservative estimate. + pub UnitWeightCost: Weight = 1_000_000_000; // One ROC buys 1 second of weight. pub const WeightPrice: (MultiLocation, u128) = (MultiLocation::parent(), ROC); pub const MaxInstructions: u32 = 100; @@ -376,11 +379,19 @@ pub type Barrier = ( AllowUnpaidExecutionFrom, // ^^^ Parent & its unit plurality gets free execution AllowUnpaidExecutionFrom, + // Expected responses are OK. + AllowKnownQueryResponses, + // Subscriptions for version tracking are OK. + AllowSubscriptionsFrom, ); parameter_types! { - pub StatemintLocation: MultiLocation = MultiLocation::new(1, X1(Parachain(1000))); pub MaxAssetsIntoHolding: u32 = 64; + pub StatemintLocation: MultiLocation = MultiLocation::new(1, X1(Parachain(1000))); + // ALWAYS ensure that the index in PalletInstance stays up-to-date with + // Statemint's Assets pallet index + pub StatemintAssetsPalletLocation: MultiLocation = + MultiLocation::new(1, X2(Parachain(1000), PalletInstance(50))); } pub type Reserves = (NativeAsset, AssetsFrom); @@ -445,6 +456,7 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime { type XcmExecutor = XcmExecutor; type ChannelInfo = ParachainSystem; type VersionWrapper = (); + type ExecuteOverweightOrigin = EnsureRoot; } impl cumulus_pallet_dmp_queue::Config for Runtime { @@ -462,6 +474,7 @@ impl cumulus_ping::Config for Runtime { parameter_types! { pub const AssetDeposit: Balance = 1 * ROC; + pub const AssetAccountDeposit: Balance = 1 * ROC; pub const ApprovalDeposit: Balance = 100 * MILLIROC; pub const AssetsStringLimit: u32 = 50; pub const MetadataDepositBase: Balance = 1 * ROC; @@ -471,11 +484,8 @@ parameter_types! { } /// A majority of the Unit body from Rococo over XCM is our required administration origin. -pub type AdminOrigin = EnsureOneOf< - AccountId, - EnsureRoot, - EnsureXcm>, ->; +pub type AdminOrigin = + EnsureOneOf, EnsureXcm>>; impl pallet_assets::Config for Runtime { type Event = Event; @@ -491,6 +501,7 @@ impl pallet_assets::Config for Runtime { type Freezer = (); type Extra = (); type WeightInfo = pallet_assets::weights::SubstrateWeight; + type AssetAccountDeposit = AssetAccountDeposit; } impl pallet_aura::Config for Runtime { @@ -508,7 +519,6 @@ construct_runtime! { System: frame_system::{Pallet, Call, Storage, Config, Event}, Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent}, Sudo: pallet_sudo::{Pallet, Call, Storage, Config, Event}, - RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Pallet, Storage}, TransactionPayment: pallet_transaction_payment::{Pallet, Storage}, ParachainSystem: cumulus_pallet_parachain_system::{ @@ -557,6 +567,7 @@ pub type SignedBlock = generic::SignedBlock; pub type BlockId = generic::BlockId; /// The SignedExtension to the basic transaction logic. pub type SignedExtra = ( + frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckGenesis, frame_system::CheckEra, @@ -574,9 +585,20 @@ pub type Executive = frame_executive::Executive< Block, frame_system::ChainContext, Runtime, - AllPallets, + AllPalletsWithSystem, + RemoveCollectiveFlip, >; +pub struct RemoveCollectiveFlip; +impl frame_support::traits::OnRuntimeUpgrade for RemoveCollectiveFlip { + fn on_runtime_upgrade() -> Weight { + use frame_support::storage::migration; + // Remove the storage value `RandomMaterial` from removed pallet `RandomnessCollectiveFlip` + migration::remove_storage_prefix(b"RandomnessCollectiveFlip", b"RandomMaterial", b""); + ::DbWeight::get().writes(1) + } +} + impl_runtime_apis! { impl sp_api::Core for Runtime { fn version() -> RuntimeVersion { diff --git a/test/runtime-upgrade/Cargo.toml b/polkadot-parachains/seedling/Cargo.toml similarity index 78% rename from test/runtime-upgrade/Cargo.toml rename to polkadot-parachains/seedling/Cargo.toml index efe9206196..5f9c517339 100644 --- a/test/runtime-upgrade/Cargo.toml +++ b/polkadot-parachains/seedling/Cargo.toml @@ -1,70 +1,66 @@ [package] -name = "cumulus-test-runtime-upgrade" -version = "0.1.0" +name = 'seedling-runtime' +version = '0.1.0' authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" [dependencies] codec = { package = "parity-scale-codec", version = "2.3.0", default-features = false, features = ["derive"] } +log = { version = "0.4.14", default-features = false } +parachain-info = { path = "../pallets/parachain-info", default-features = false } scale-info = { version = "1.0.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.101", optional = true, features = ["derive"] } +serde = { version = "1.0.132", optional = true, features = ["derive"] } # Substrate dependencies -frame-executive = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } -frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } -frame-system = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } -pallet-balances = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } -pallet-randomness-collective-flip = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } -pallet-sudo = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } -pallet-timestamp = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } -pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } -sp-api = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } -sp-block-builder = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } -sp-core = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } -sp-inherents = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } -sp-io = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } -sp-offchain = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } -sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } -sp-session = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } -sp-transaction-pool = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } +sp-api = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } +sp-io = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } sp-version = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } +sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } +sp-core = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } +sp-session = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } +sp-offchain = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } +sp-block-builder = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } +sp-transaction-pool = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } +sp-inherents = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } + +frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } +frame-executive = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } +frame-system = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } +pallet-sudo = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } +pallet-balances = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } # Cumulus dependencies cumulus-pallet-parachain-system = { path = "../../pallets/parachain-system", default-features = false } cumulus-primitives-core = { path = "../../primitives/core", default-features = false } -cumulus-primitives-timestamp = { path = "../../primitives/timestamp", default-features = false } [build-dependencies] substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", branch = "master" } [features] -default = [ "std", "upgrade" ] +default = [ "std" ] std = [ "codec/std", "scale-info/std", + "serde", + "log/std", + "sp-api/std", + "sp-std/std", + "sp-io/std", + "sp-core/std", + "sp-runtime/std", + "sp-version/std", + "sp-offchain/std", + "sp-session/std", + "sp-block-builder/std", + "sp-transaction-pool/std", + "sp-inherents/std", + "frame-support/std", + "frame-executive/std", + "frame-system/std", + "pallet-sudo/std", + "pallet-balances/std", + "parachain-info/std", "cumulus-pallet-parachain-system/std", "cumulus-primitives-core/std", - "cumulus-primitives-timestamp/std", - "frame-executive/std", - "frame-support/std", - "frame-system/std", - "pallet-balances/std", - "pallet-randomness-collective-flip/std", - "pallet-sudo/std", - "pallet-timestamp/std", - "pallet-transaction-payment/std", - "serde", - "sp-api/std", - "sp-block-builder/std", - "sp-core/std", - "sp-inherents/std", - "sp-io/std", - "sp-offchain/std", - "sp-runtime/std", - "sp-session/std", - "sp-std/std", - "sp-transaction-pool/std", - "sp-version/std", ] -upgrade = [] diff --git a/polkadot-parachains/seedling/build.rs b/polkadot-parachains/seedling/build.rs new file mode 100644 index 0000000000..fe1a2ea911 --- /dev/null +++ b/polkadot-parachains/seedling/build.rs @@ -0,0 +1,25 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . + +use substrate_wasm_builder::WasmBuilder; + +fn main() { + WasmBuilder::new() + .with_current_project() + .export_heap_base() + .import_memory() + .build() +} diff --git a/polkadot-parachains/seedling/src/lib.rs b/polkadot-parachains/seedling/src/lib.rs new file mode 100644 index 0000000000..fb10260421 --- /dev/null +++ b/polkadot-parachains/seedling/src/lib.rs @@ -0,0 +1,327 @@ +// Copyright 2019-2021 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_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")); + +use sp_api::impl_runtime_apis; +use sp_core::OpaqueMetadata; +use sp_runtime::{ + create_runtime_str, generic, + traits::{AccountIdLookup, BlakeTwo256, Block as BlockT}, + transaction_validity::{TransactionSource, TransactionValidity}, + ApplyExtrinsicResult, +}; +use sp_std::prelude::*; +#[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, match_type, parameter_types, + traits::{Contains, IsInVec, Randomness}, + weights::{ + constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND}, + DispatchClass, IdentityFee, Weight, + }, + StorageValue, +}; +use frame_system::limits::{BlockLength, BlockWeights}; +#[cfg(any(feature = "std", test))] +pub use sp_runtime::BuildStorage; +pub use sp_runtime::{Perbill, Permill}; + +/// 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: 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() } +} + +/// 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_PER_SECOND / 2; + +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; +} + +pub struct BaseFilter; +impl Contains for BaseFilter { + fn contains(c: &Call) -> bool { + // Disallow everything that is not set_validation_data or set_code + match c { + Call::ParachainSystem(cumulus_pallet_parachain_system::Call::set_validation_data { + .. + }) => true, + Call::Sudo(pallet_sudo::Call::sudo_unchecked_weight { call: ref x, .. }) => { + matches!(x.as_ref(), &Call::System(frame_system::Call::set_code { .. })) + }, + _ => false, + } + } +} + +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 Call = Call; + /// 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 Index = Index; + /// The index type for blocks. + type BlockNumber = BlockNumber; + /// The type for hashing blocks and tries. + type Hash = Hash; + /// The hashing algorithm used. + type Hashing = BlakeTwo256; + /// The header type. + type Header = generic::Header; + /// The ubiquitous event type. + type Event = Event; + /// The ubiquitous origin type. + type Origin = Origin; + /// 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 = BaseFilter; + 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 Call = Call; + type Event = Event; +} + +impl cumulus_pallet_parachain_system::Config for Runtime { + type Event = Event; + type OnValidationData = (); + type SelfParaId = parachain_info::Pallet; + type OutboundXcmpMessageSource = (); + type DmpMessageHandler = (); + type ReservedDmpWeight = (); + type XcmpMessageHandler = (); + type ReservedXcmpWeight = (); +} + +impl parachain_info::Config for Runtime {} + +construct_runtime! { + pub enum Runtime where + Block = Block, + NodeBlock = generic::Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system::{Pallet, Call, Storage, Config, Event}, + Sudo: pallet_sudo::{Pallet, Call, Storage, Config, Event}, + ParachainSystem: cumulus_pallet_parachain_system::{ + Pallet, Call, Config, Storage, Inherent, Event, ValidateUnsigned, + }, + ParachainInfo: parachain_info::{Pallet, Storage, Config}, + } +} + +/// Alias to 512-bit hash when used in the context of a transaction signature on the chain. +pub type Signature = sp_runtime::MultiSignature; +/// Some way of identifying an account on the chain. We intentionally make it equivalent +/// to the public key of our transaction signing scheme. +pub type AccountId = <::Signer as sp_runtime::traits::IdentifyAccount>::AccountId; +/// Index of a transaction in the chain. +pub type Index = 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, +); +/// Unchecked extrinsic type as expected by this runtime. +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +/// Extrinsic type that has already been checked. +pub type CheckedExtrinsic = generic::CheckedExtrinsic; +/// 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_api::Core for Runtime { + fn version() -> RuntimeVersion { + VERSION + } + + fn execute_block(block: Block) { + Executive::execute_block(block) + } + + fn initialize_block(header: &::Header) { + Executive::initialize_block(header) + } + } + + impl sp_api::Metadata for Runtime { + fn metadata() -> OpaqueMetadata { + OpaqueMetadata::new(Runtime::metadata().into()) + } + } + + 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 decode_session_keys(_: Vec) -> Option, sp_core::crypto::KeyTypeId)>> { + Some(Vec::new()) + } + + fn generate_session_keys(_: Option>) -> Vec { + Vec::new() + } + } + + impl cumulus_primitives_core::CollectCollationInfo for Runtime { + fn collect_collation_info() -> cumulus_primitives_core::CollationInfo { + ParachainSystem::collect_collation_info() + } + } +} + +struct CheckInherents; + +impl cumulus_pallet_parachain_system::CheckInherents for CheckInherents { + fn check_inherents( + _: &Block, + _: &cumulus_pallet_parachain_system::RelayChainStateProof, + ) -> sp_inherents::CheckInherentsResult { + sp_inherents::CheckInherentsResult::new() + } +} + +cumulus_pallet_parachain_system::register_validate_block! { + Runtime = Runtime, + BlockExecutor = Executive, + CheckInherents = CheckInherents, +} diff --git a/polkadot-parachains/shell/Cargo.toml b/polkadot-parachains/shell/Cargo.toml index 2a0edf2335..1a06452bec 100644 --- a/polkadot-parachains/shell/Cargo.toml +++ b/polkadot-parachains/shell/Cargo.toml @@ -1,15 +1,15 @@ [package] -name = 'shell-runtime' -version = '0.1.0' +name = "shell-runtime" +version = "0.1.0" authors = ["Parity Technologies "] -edition = '2018' +edition = "2021" [dependencies] codec = { package = "parity-scale-codec", version = "2.3.0", default-features = false, features = ["derive"] } log = { version = "0.4.14", default-features = false } parachain-info = { path = "../pallets/parachain-info", default-features = false } scale-info = { version = "1.0.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.101", optional = true, features = ["derive"] } +serde = { version = "1.0.132", optional = true, features = ["derive"] } # Substrate dependencies sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } @@ -28,6 +28,9 @@ frame-support = { git = "https://github.com/paritytech/substrate", default-featu frame-executive = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } frame-system = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } +# try-runtime stuff. +frame-try-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true } + # Cumulus dependencies cumulus-pallet-parachain-system = { path = "../../pallets/parachain-system", default-features = false } cumulus-primitives-core = { path = "../../primitives/core", default-features = false } @@ -72,3 +75,7 @@ std = [ "xcm-builder/std", "xcm-executor/std", ] +try-runtime = [ + "frame-try-runtime", + "frame-executive/try-runtime", +] diff --git a/polkadot-parachains/shell/src/lib.rs b/polkadot-parachains/shell/src/lib.rs index a202afd63d..3bef82574d 100644 --- a/polkadot-parachains/shell/src/lib.rs +++ b/polkadot-parachains/shell/src/lib.rs @@ -23,12 +23,13 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); use codec::{Decode, Encode}; +use frame_support::unsigned::TransactionValidityError; use scale_info::TypeInfo; use sp_api::impl_runtime_apis; use sp_core::OpaqueMetadata; use sp_runtime::{ create_runtime_str, generic, - traits::{AccountIdLookup, BlakeTwo256, Block as BlockT}, + traits::{AccountIdLookup, BlakeTwo256, Block as BlockT, DispatchInfoOf}, transaction_validity::{TransactionSource, TransactionValidity}, ApplyExtrinsicResult, }; @@ -70,6 +71,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, + state_version: 0, }; /// The version information used to identify this runtime when compiled natively. @@ -150,6 +152,7 @@ impl frame_system::Config for Runtime { type BlockLength = RuntimeBlockLength; type SS58Prefix = SS58Prefix; type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { @@ -194,8 +197,8 @@ match_type! { } parameter_types! { - // One XCM operation is 1_000_000 weight - almost certainly a conservative estimate. - pub UnitWeightCost: Weight = 1_000_000; + // One XCM operation is 1_000_000_000 weight - almost certainly a conservative estimate. + pub UnitWeightCost: Weight = 1_000_000_000; pub const MaxInstructions: u32 = 100; pub const MaxAssetsIntoHolding: u32 = 64; } @@ -256,6 +259,15 @@ impl sp_runtime::traits::SignedExtension for DisallowSigned { ) -> sp_std::result::Result<(), sp_runtime::transaction_validity::TransactionValidityError> { Ok(()) } + fn pre_dispatch( + self, + who: &Self::AccountId, + call: &Self::Call, + info: &DispatchInfoOf, + len: usize, + ) -> Result { + Ok(self.validate(who, call, info, len).map(|_| ())?) + } fn validate( &self, _who: &Self::AccountId, @@ -301,7 +313,7 @@ pub type Executive = frame_executive::Executive< Block, frame_system::ChainContext, Runtime, - AllPallets, + AllPalletsWithSystem, >; impl_runtime_apis! { diff --git a/polkadot-parachains/src/chain_spec.rs b/polkadot-parachains/src/chain_spec.rs index 3c00a8f6df..8ae25afbdd 100644 --- a/polkadot-parachains/src/chain_spec.rs +++ b/polkadot-parachains/src/chain_spec.rs @@ -30,6 +30,10 @@ pub type ChainSpec = /// Specialized `ChainSpec` for the shell parachain runtime. pub type ShellChainSpec = sc_service::GenericChainSpec; +/// Specialized `ChainSpec` for the seedling parachain runtime. +pub type SeedlingChainSpec = + 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) @@ -64,7 +68,7 @@ where AccountPublic::from(get_from_seed::(seed)).into_account() } -pub fn get_chain_spec(id: ParaId) -> ChainSpec { +pub fn get_chain_spec() -> ChainSpec { ChainSpec::from_genesis( "Local Testnet", "local_testnet", @@ -87,32 +91,51 @@ pub fn get_chain_spec(id: ParaId) -> ChainSpec { get_account_id_from_seed::("Eve//stash"), get_account_id_from_seed::("Ferdie//stash"), ], - id, + 1000.into(), ) }, - vec![], + Vec::new(), None, None, None, - Extensions { relay_chain: "westend".into(), para_id: id.into() }, + Extensions { relay_chain: "westend".into(), para_id: 1000 }, ) } -pub fn get_shell_chain_spec(id: ParaId) -> ShellChainSpec { +pub fn get_shell_chain_spec() -> ShellChainSpec { ShellChainSpec::from_genesis( "Shell Local Testnet", "shell_local_testnet", ChainType::Local, - move || shell_testnet_genesis(id), - vec![], + move || shell_testnet_genesis(1000.into()), + Vec::new(), None, None, None, - Extensions { relay_chain: "westend".into(), para_id: id.into() }, + Extensions { relay_chain: "westend".into(), para_id: 1000 }, ) } -pub fn staging_test_net(id: ParaId) -> ChainSpec { +pub fn get_seedling_chain_spec() -> SeedlingChainSpec { + SeedlingChainSpec::from_genesis( + "Seedling Local Testnet", + "seedling_local_testnet", + ChainType::Local, + move || { + seedling_testnet_genesis( + get_account_id_from_seed::("Alice"), + 2000.into(), + ) + }, + Vec::new(), + None, + None, + None, + Extensions { relay_chain: "westend".into(), para_id: 2000 }, + ) +} + +pub fn staging_test_net() -> ChainSpec { ChainSpec::from_genesis( "Staging Testnet", "staging_testnet", @@ -131,14 +154,14 @@ pub fn staging_test_net(id: ParaId) -> ChainSpec { vec![ hex!["9ed7705e3c7da027ba0583a22a3212042f7e715d3c168ba14f1424e2bc111d00"].into() ], - id, + 1000.into(), ) }, Vec::new(), None, None, None, - Extensions { relay_chain: "westend".into(), para_id: id.into() }, + Extensions { relay_chain: "westend".into(), para_id: 1000 }, ) } @@ -153,12 +176,11 @@ fn testnet_genesis( code: rococo_parachain_runtime::WASM_BINARY .expect("WASM binary was not build, please build it!") .to_vec(), - changes_trie_config: Default::default(), }, balances: rococo_parachain_runtime::BalancesConfig { balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(), }, - sudo: rococo_parachain_runtime::SudoConfig { key: root_key }, + sudo: rococo_parachain_runtime::SudoConfig { key: Some(root_key) }, parachain_info: rococo_parachain_runtime::ParachainInfoConfig { parachain_id: id }, aura: rococo_parachain_runtime::AuraConfig { authorities: initial_authorities }, aura_ext: Default::default(), @@ -172,13 +194,28 @@ fn shell_testnet_genesis(parachain_id: ParaId) -> shell_runtime::GenesisConfig { code: shell_runtime::WASM_BINARY .expect("WASM binary was not build, please build it!") .to_vec(), - changes_trie_config: Default::default(), }, parachain_info: shell_runtime::ParachainInfoConfig { parachain_id }, parachain_system: Default::default(), } } +fn seedling_testnet_genesis( + root_key: AccountId, + parachain_id: ParaId, +) -> seedling_runtime::GenesisConfig { + seedling_runtime::GenesisConfig { + system: seedling_runtime::SystemConfig { + code: seedling_runtime::WASM_BINARY + .expect("WASM binary was not build, please build it!") + .to_vec(), + }, + sudo: seedling_runtime::SudoConfig { key: Some(root_key) }, + parachain_info: seedling_runtime::ParachainInfoConfig { parachain_id }, + parachain_system: Default::default(), + } +} + use parachains_common::Balance as StatemintBalance; /// Specialized `ChainSpec` for the normal parachain runtime. @@ -194,7 +231,7 @@ const STATEMINE_ED: StatemintBalance = statemine_runtime::constants::currency::E const WESTMINT_ED: StatemintBalance = westmint_runtime::constants::currency::EXISTENTIAL_DEPOSIT; /// Helper function to generate a crypto pair from seed -pub fn get_pair_from_seed(seed: &str) -> ::Public { +pub fn get_public_from_seed(seed: &str) -> ::Public { TPublic::Pair::from_string(&format!("//{}", seed), None) .expect("static values are valid; qed") .public() @@ -204,7 +241,7 @@ pub fn get_pair_from_seed(seed: &str) -> AuraId { - get_pair_from_seed::(seed) + get_public_from_seed::(seed) } /// Generate the session keys from individual elements. @@ -228,7 +265,7 @@ pub fn westmint_session_keys(keys: AuraId) -> westmint_runtime::SessionKeys { westmint_runtime::SessionKeys { aura: keys } } -pub fn statemint_development_config(id: ParaId) -> StatemintChainSpec { +pub fn statemint_development_config() -> StatemintChainSpec { let mut properties = sc_chain_spec::Properties::new(); properties.insert("tokenSymbol".into(), "DOT".into()); properties.insert("tokenDecimals".into(), 10.into()); @@ -252,18 +289,18 @@ pub fn statemint_development_config(id: ParaId) -> StatemintChainSpec { get_account_id_from_seed::("Alice//stash"), get_account_id_from_seed::("Bob//stash"), ], - id, + 1000.into(), ) }, - vec![], + Vec::new(), None, None, Some(properties), - Extensions { relay_chain: "polkadot-dev".into(), para_id: id.into() }, + Extensions { relay_chain: "polkadot-dev".into(), para_id: 1000 }, ) } -pub fn statemint_local_config(id: ParaId) -> StatemintChainSpec { +pub fn statemint_local_config() -> StatemintChainSpec { let mut properties = sc_chain_spec::Properties::new(); properties.insert("tokenSymbol".into(), "DOT".into()); properties.insert("tokenDecimals".into(), 10.into()); @@ -301,14 +338,14 @@ pub fn statemint_local_config(id: ParaId) -> StatemintChainSpec { get_account_id_from_seed::("Eve//stash"), get_account_id_from_seed::("Ferdie//stash"), ], - id, + 1000.into(), ) }, - vec![], + Vec::new(), None, None, Some(properties), - Extensions { relay_chain: "polkadot-local".into(), para_id: id.into() }, + Extensions { relay_chain: "polkadot-local".into(), para_id: 1000 }, ) } @@ -322,7 +359,6 @@ fn statemint_genesis( code: statemint_runtime::WASM_BINARY .expect("WASM binary was not build, please build it!") .to_vec(), - changes_trie_config: Default::default(), }, balances: statemint_runtime::BalancesConfig { balances: endowed_accounts.iter().cloned().map(|k| (k, STATEMINT_ED * 4096)).collect(), @@ -335,12 +371,11 @@ fn statemint_genesis( }, session: statemint_runtime::SessionConfig { keys: invulnerables - .iter() - .cloned() + .into_iter() .map(|(acc, aura)| { ( acc.clone(), // account id - acc.clone(), // validator id + acc, // validator id statemint_session_keys(aura), // session keys ) }) @@ -354,8 +389,9 @@ fn statemint_genesis( } } -pub fn statemine_development_config(id: ParaId) -> StatemineChainSpec { +pub fn statemine_development_config() -> StatemineChainSpec { let mut properties = sc_chain_spec::Properties::new(); + properties.insert("ss58Format".into(), 2.into()); properties.insert("tokenSymbol".into(), "KSM".into()); properties.insert("tokenDecimals".into(), 12.into()); @@ -378,19 +414,20 @@ pub fn statemine_development_config(id: ParaId) -> StatemineChainSpec { get_account_id_from_seed::("Alice//stash"), get_account_id_from_seed::("Bob//stash"), ], - id, + 1000.into(), ) }, - vec![], + Vec::new(), None, None, Some(properties), - Extensions { relay_chain: "kusama-dev".into(), para_id: id.into() }, + Extensions { relay_chain: "kusama-dev".into(), para_id: 1000 }, ) } -pub fn statemine_local_config(id: ParaId) -> StatemineChainSpec { +pub fn statemine_local_config() -> StatemineChainSpec { let mut properties = sc_chain_spec::Properties::new(); + properties.insert("ss58Format".into(), 2.into()); properties.insert("tokenSymbol".into(), "KSM".into()); properties.insert("tokenDecimals".into(), 12.into()); @@ -427,19 +464,20 @@ pub fn statemine_local_config(id: ParaId) -> StatemineChainSpec { get_account_id_from_seed::("Eve//stash"), get_account_id_from_seed::("Ferdie//stash"), ], - id, + 1000.into(), ) }, - vec![], + Vec::new(), None, None, Some(properties), - Extensions { relay_chain: "kusama-local".into(), para_id: id.into() }, + Extensions { relay_chain: "kusama-local".into(), para_id: 1000 }, ) } -pub fn statemine_config(id: ParaId) -> StatemineChainSpec { +pub fn statemine_config() -> StatemineChainSpec { let mut properties = sc_chain_spec::Properties::new(); + properties.insert("ss58Format".into(), 2.into()); properties.insert("tokenSymbol".into(), "KSM".into()); properties.insert("tokenDecimals".into(), 12.into()); @@ -478,15 +516,15 @@ pub fn statemine_config(id: ParaId) -> StatemineChainSpec { .unchecked_into(), ), ], - vec![], - id, + Vec::new(), + 1000.into(), ) }, - vec![], + Vec::new(), None, None, Some(properties), - Extensions { relay_chain: "kusama".into(), para_id: id.into() }, + Extensions { relay_chain: "kusama".into(), para_id: 1000 }, ) } @@ -500,10 +538,13 @@ fn statemine_genesis( code: statemine_runtime::WASM_BINARY .expect("WASM binary was not build, please build it!") .to_vec(), - changes_trie_config: Default::default(), }, balances: statemine_runtime::BalancesConfig { - balances: endowed_accounts.iter().cloned().map(|k| (k, STATEMINE_ED * 4096)).collect(), + balances: endowed_accounts + .iter() + .cloned() + .map(|k| (k, STATEMINE_ED * 524_288)) + .collect(), }, parachain_info: statemine_runtime::ParachainInfoConfig { parachain_id: id }, collator_selection: statemine_runtime::CollatorSelectionConfig { @@ -513,12 +554,11 @@ fn statemine_genesis( }, session: statemine_runtime::SessionConfig { keys: invulnerables - .iter() - .cloned() + .into_iter() .map(|(acc, aura)| { ( acc.clone(), // account id - acc.clone(), // validator id + acc, // validator id statemine_session_keys(aura), // session keys ) }) @@ -530,7 +570,7 @@ fn statemine_genesis( } } -pub fn westmint_development_config(id: ParaId) -> WestmintChainSpec { +pub fn westmint_development_config() -> WestmintChainSpec { let mut properties = sc_chain_spec::Properties::new(); properties.insert("tokenSymbol".into(), "WND".into()); properties.insert("tokenDecimals".into(), 12.into()); @@ -555,18 +595,18 @@ pub fn westmint_development_config(id: ParaId) -> WestmintChainSpec { get_account_id_from_seed::("Bob//stash"), ], get_account_id_from_seed::("Alice"), - id, + 1000.into(), ) }, - vec![], + Vec::new(), None, None, Some(properties), - Extensions { relay_chain: "westend".into(), para_id: id.into() }, + Extensions { relay_chain: "westend".into(), para_id: 1000 }, ) } -pub fn westmint_local_config(id: ParaId) -> WestmintChainSpec { +pub fn westmint_local_config() -> WestmintChainSpec { let mut properties = sc_chain_spec::Properties::new(); properties.insert("tokenSymbol".into(), "WND".into()); properties.insert("tokenDecimals".into(), 12.into()); @@ -605,18 +645,18 @@ pub fn westmint_local_config(id: ParaId) -> WestmintChainSpec { get_account_id_from_seed::("Ferdie//stash"), ], get_account_id_from_seed::("Alice"), - id, + 1000.into(), ) }, - vec![], + Vec::new(), None, None, Some(properties), - Extensions { relay_chain: "westend-local".into(), para_id: id.into() }, + Extensions { relay_chain: "westend-local".into(), para_id: 1000 }, ) } -pub fn westmint_config(id: ParaId) -> WestmintChainSpec { +pub fn westmint_config() -> WestmintChainSpec { let mut properties = sc_chain_spec::Properties::new(); properties.insert("tokenSymbol".into(), "WND".into()); properties.insert("tokenDecimals".into(), 12.into()); @@ -656,17 +696,17 @@ pub fn westmint_config(id: ParaId) -> WestmintChainSpec { .unchecked_into(), ), ], - vec![], + Vec::new(), // re-use the Westend sudo key hex!("6648d7f3382690650c681aba1b993cd11e54deb4df21a3a18c3e2177de9f7342").into(), - id, + 1000.into(), ) }, - vec![], + Vec::new(), None, None, Some(properties), - Extensions { relay_chain: "westend".into(), para_id: id.into() }, + Extensions { relay_chain: "westend".into(), para_id: 1000 }, ) } @@ -681,12 +721,11 @@ fn westmint_genesis( code: westmint_runtime::WASM_BINARY .expect("WASM binary was not build, please build it!") .to_vec(), - changes_trie_config: Default::default(), }, balances: westmint_runtime::BalancesConfig { balances: endowed_accounts.iter().cloned().map(|k| (k, WESTMINT_ED * 4096)).collect(), }, - sudo: westmint_runtime::SudoConfig { key: root_key }, + sudo: westmint_runtime::SudoConfig { key: Some(root_key) }, parachain_info: westmint_runtime::ParachainInfoConfig { parachain_id: id }, collator_selection: westmint_runtime::CollatorSelectionConfig { invulnerables: invulnerables.iter().cloned().map(|(acc, _)| acc).collect(), @@ -695,12 +734,11 @@ fn westmint_genesis( }, session: westmint_runtime::SessionConfig { keys: invulnerables - .iter() - .cloned() + .into_iter() .map(|(acc, aura)| { ( acc.clone(), // account id - acc.clone(), // validator id + acc, // validator id westmint_session_keys(aura), // session keys ) }) diff --git a/polkadot-parachains/src/cli.rs b/polkadot-parachains/src/cli.rs index 0b4bf72032..900335fb94 100644 --- a/polkadot-parachains/src/cli.rs +++ b/polkadot-parachains/src/cli.rs @@ -55,6 +55,9 @@ pub enum Subcommand { #[structopt(name = "benchmark", about = "Benchmark runtime pallets.")] Benchmark(frame_benchmarking_cli::BenchmarkCmd), + /// Try some testing command against a specified runtime state. + TryRuntime(try_runtime_cli::TryRuntimeCmd), + /// Key management CLI utilities Key(sc_cli::KeySubcommand), } @@ -110,7 +113,7 @@ pub struct Cli { #[structopt(flatten)] pub run: cumulus_client_cli::RunCmd, - /// Relaychain arguments + /// Relay chain arguments #[structopt(raw = true)] pub relaychain_args: Vec, } diff --git a/polkadot-parachains/src/command.rs b/polkadot-parachains/src/command.rs index 753f1bbc5d..454eeb1236 100644 --- a/polkadot-parachains/src/command.rs +++ b/polkadot-parachains/src/command.rs @@ -18,8 +18,9 @@ use crate::{ chain_spec, cli::{Cli, RelayChainCli, Subcommand}, service::{ - new_partial, Block, RococoParachainRuntimeExecutor, ShellRuntimeExecutor, - StatemineRuntimeExecutor, StatemintRuntimeExecutor, WestmintRuntimeExecutor, + new_partial, Block, RococoParachainRuntimeExecutor, SeedlingRuntimeExecutor, + ShellRuntimeExecutor, StatemineRuntimeExecutor, StatemintRuntimeExecutor, + WestmintRuntimeExecutor, }, }; use codec::Encode; @@ -31,16 +32,17 @@ use sc_cli::{ ChainSpec, CliConfiguration, DefaultConfigurationValues, ImportParams, KeystoreParams, NetworkParams, Result, RuntimeVersion, SharedParams, SubstrateCli, }; -use sc_service::config::{BasePath, PrometheusConfig}; +use sc_service::{ + config::{BasePath, PrometheusConfig}, + TaskManager, +}; use sp_core::hexdisplay::HexDisplay; use sp_runtime::traits::Block as BlockT; use std::{io::Write, net::SocketAddr}; -// default to the Statemint/Statemine/Westmint id -const DEFAULT_PARA_ID: u32 = 1000; - trait IdentifyChain { fn is_shell(&self) -> bool; + fn is_seedling(&self) -> bool; fn is_statemint(&self) -> bool; fn is_statemine(&self) -> bool; fn is_westmint(&self) -> bool; @@ -50,6 +52,9 @@ impl IdentifyChain for dyn sc_service::ChainSpec { fn is_shell(&self) -> bool { self.id().starts_with("shell") } + fn is_seedling(&self) -> bool { + self.id().starts_with("seedling") + } fn is_statemint(&self) -> bool { self.id().starts_with("statemint") } @@ -65,6 +70,9 @@ impl IdentifyChain for T { fn is_shell(&self) -> bool { ::is_shell(self) } + fn is_seedling(&self) -> bool { + ::is_seedling(self) + } fn is_statemint(&self) -> bool { ::is_statemint(self) } @@ -76,12 +84,9 @@ impl IdentifyChain for T { } } -fn load_spec( - id: &str, - para_id: ParaId, -) -> std::result::Result, String> { +fn load_spec(id: &str) -> std::result::Result, String> { Ok(match id { - "staging" => Box::new(chain_spec::staging_test_net(para_id)), + "staging" => Box::new(chain_spec::staging_test_net()), "tick" => Box::new(chain_spec::ChainSpec::from_json_bytes( &include_bytes!("../res/tick.json")[..], )?), @@ -91,26 +96,27 @@ fn load_spec( "track" => Box::new(chain_spec::ChainSpec::from_json_bytes( &include_bytes!("../res/track.json")[..], )?), - "shell" => Box::new(chain_spec::get_shell_chain_spec(para_id)), - "statemint-dev" => Box::new(chain_spec::statemint_development_config(para_id)), - "statemint-local" => Box::new(chain_spec::statemint_local_config(para_id)), - "statemine-dev" => Box::new(chain_spec::statemine_development_config(para_id)), - "statemine-local" => Box::new(chain_spec::statemine_local_config(para_id)), + "shell" => Box::new(chain_spec::get_shell_chain_spec()), + "seedling" => Box::new(chain_spec::get_seedling_chain_spec()), + "statemint-dev" => Box::new(chain_spec::statemint_development_config()), + "statemint-local" => Box::new(chain_spec::statemint_local_config()), + "statemine-dev" => Box::new(chain_spec::statemine_development_config()), + "statemine-local" => Box::new(chain_spec::statemine_local_config()), // the chain spec as used for generating the upgrade genesis values - "statemine-genesis" => Box::new(chain_spec::statemine_config(para_id)), + "statemine-genesis" => Box::new(chain_spec::statemine_config()), // the shell-based chain spec as used for syncing "statemine" => Box::new(chain_spec::ChainSpec::from_json_bytes( &include_bytes!("../res/statemine.json")[..], )?), - "westmint-dev" => Box::new(chain_spec::westmint_development_config(para_id)), - "westmint-local" => Box::new(chain_spec::westmint_local_config(para_id)), + "westmint-dev" => Box::new(chain_spec::westmint_development_config()), + "westmint-local" => Box::new(chain_spec::westmint_local_config()), // the chain spec as used for generating the upgrade genesis values - "westmint-genesis" => Box::new(chain_spec::westmint_config(para_id)), + "westmint-genesis" => Box::new(chain_spec::westmint_config()), // the shell-based chain spec as used for syncing "westmint" => Box::new(chain_spec::ChainSpec::from_json_bytes( &include_bytes!("../res/westmint.json")[..], )?), - "" => Box::new(chain_spec::get_chain_spec(para_id)), + "" => Box::new(chain_spec::get_chain_spec()), path => { let chain_spec = chain_spec::ChainSpec::from_json_file(path.into())?; if chain_spec.is_statemint() { @@ -121,6 +127,8 @@ fn load_spec( Box::new(chain_spec::WestmintChainSpec::from_json_file(path.into())?) } else if chain_spec.is_shell() { Box::new(chain_spec::ShellChainSpec::from_json_file(path.into())?) + } else if chain_spec.is_seedling() { + Box::new(chain_spec::SeedlingChainSpec::from_json_file(path.into())?) } else { Box::new(chain_spec) } @@ -160,7 +168,7 @@ impl SubstrateCli for Cli { } fn load_spec(&self, id: &str) -> std::result::Result, String> { - load_spec(id, self.run.parachain_id.unwrap_or(DEFAULT_PARA_ID).into()) + load_spec(id) } fn native_runtime_version(chain_spec: &Box) -> &'static RuntimeVersion { @@ -172,6 +180,8 @@ impl SubstrateCli for Cli { &westmint_runtime::VERSION } else if chain_spec.is_shell() { &shell_runtime::VERSION + } else if chain_spec.is_seedling() { + &seedling_runtime::VERSION } else { &rococo_parachain_runtime::VERSION } @@ -191,8 +201,8 @@ impl SubstrateCli for RelayChainCli { format!( "Polkadot collator\n\nThe command-line arguments provided first will be \ passed to the parachain node, while the arguments provided after -- will be passed \ - to the relaychain node.\n\n\ - {} [parachain-args] -- [relaychain-args]", + to the relay chain node.\n\n\ + {} [parachain-args] -- [relay_chain-args]", Self::executable_name() ) } @@ -267,6 +277,15 @@ macro_rules! construct_async_run { let task_manager = $components.task_manager; { $( $code )* }.map(|v| (v, task_manager)) }) + } else if runner.config().chain_spec.is_seedling() { + runner.async_run(|$config| { + let $components = new_partial::( + &$config, + crate::service::shell_build_import_queue, + )?; + let task_manager = $components.task_manager; + { $( $code )* }.map(|v| (v, task_manager)) + }) } else { runner.async_run(|$config| { let $components = new_partial::< @@ -342,10 +361,10 @@ pub fn run() -> Result<()> { builder.with_profiling(sc_tracing::TracingReceiver::Log, ""); let _ = builder.init(); - let block: crate::service::Block = generate_genesis_block(&load_spec( - ¶ms.chain.clone().unwrap_or_default(), - params.parachain_id.unwrap_or(DEFAULT_PARA_ID).into(), - )?)?; + let spec = load_spec(¶ms.chain.clone().unwrap_or_default())?; + let state_version = Cli::native_runtime_version(&spec).state_version(); + + let block: crate::service::Block = generate_genesis_block(&spec, state_version)?; let raw_header = block.header().encode(); let output_buf = if params.raw { raw_header @@ -399,13 +418,45 @@ pub fn run() -> Result<()> { You can enable it with `--features runtime-benchmarks`." .into()) }, + Some(Subcommand::TryRuntime(cmd)) => + if cfg!(feature = "try-runtime") { + // grab the task manager. + let runner = cli.create_runner(cmd)?; + let registry = &runner.config().prometheus_config.as_ref().map(|cfg| &cfg.registry); + let task_manager = + TaskManager::new(runner.config().tokio_handle.clone(), *registry) + .map_err(|e| format!("Error: {:?}", e))?; + + if runner.config().chain_spec.is_statemine() { + runner.async_run(|config| { + Ok((cmd.run::(config), task_manager)) + }) + } else if runner.config().chain_spec.is_westmint() { + runner.async_run(|config| { + Ok((cmd.run::(config), task_manager)) + }) + } else if runner.config().chain_spec.is_statemint() { + runner.async_run(|config| { + Ok((cmd.run::(config), task_manager)) + }) + } else if runner.config().chain_spec.is_shell() { + runner.async_run(|config| { + Ok((cmd.run::(config), task_manager)) + }) + } else { + Err("Chain doesn't support try-runtime".into()) + } + } else { + Err("Try-runtime must be enabled by `--features try-runtime`.".into()) + }, Some(Subcommand::Key(cmd)) => Ok(cmd.run(&cli)?), None => { let runner = cli.create_runner(&cli.run.normalize())?; runner.run_node_until_exit(|config| async move { - let para_id = - chain_spec::Extensions::try_get(&*config.chain_spec).map(|e| e.para_id); + let para_id = chain_spec::Extensions::try_get(&*config.chain_spec) + .map(|e| e.para_id) + .ok_or_else(|| "Could not find parachain extension in chain-spec.")?; let polkadot_cli = RelayChainCli::new( &config, @@ -414,13 +465,17 @@ pub fn run() -> Result<()> { .chain(cli.relaychain_args.iter()), ); - let id = ParaId::from(cli.run.parachain_id.or(para_id).unwrap_or(DEFAULT_PARA_ID)); + let id = ParaId::from(para_id); let parachain_account = AccountIdConversion::::into_account(&id); + let state_version = + RelayChainCli::native_runtime_version(&config.chain_spec).state_version(); + let block: crate::service::Block = - generate_genesis_block(&config.chain_spec).map_err(|e| format!("{:?}", e))?; + generate_genesis_block(&config.chain_spec, state_version) + .map_err(|e| format!("{:?}", e))?; let genesis_state = format!("0x{:?}", HexDisplay::from(&block.header().encode())); let tokio_handle = config.tokio_handle.clone(); @@ -458,10 +513,21 @@ pub fn run() -> Result<()> { .map(|r| r.0) .map_err(Into::into) } else if config.chain_spec.is_shell() { - crate::service::start_shell_node(config, polkadot_config, id) - .await - .map(|r| r.0) - .map_err(Into::into) + crate::service::start_shell_node::< + shell_runtime::RuntimeApi, + ShellRuntimeExecutor, + >(config, polkadot_config, id) + .await + .map(|r| r.0) + .map_err(Into::into) + } else if config.chain_spec.is_seedling() { + crate::service::start_shell_node::< + seedling_runtime::RuntimeApi, + SeedlingRuntimeExecutor, + >(config, polkadot_config, id) + .await + .map(|r| r.0) + .map_err(Into::into) } else { crate::service::start_rococo_parachain_node(config, polkadot_config, id) .await @@ -527,11 +593,24 @@ impl CliConfiguration for RelayChainCli { self.base.base.rpc_ws(default_listen_port) } - fn prometheus_config(&self, default_listen_port: u16) -> Result> { - self.base.base.prometheus_config(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) -> Result<()> { + 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"); } diff --git a/polkadot-parachains/src/service.rs b/polkadot-parachains/src/service.rs index a896cad242..d248240a5a 100644 --- a/polkadot-parachains/src/service.rs +++ b/polkadot-parachains/src/service.rs @@ -13,13 +13,12 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -use cumulus_client_consensus_aura::{ - build_aura_consensus, BuildAuraConsensusParams, SlotProportion, -}; + +use cumulus_client_consensus_aura::{AuraConsensus, BuildAuraConsensusParams, SlotProportion}; use cumulus_client_consensus_common::{ ParachainBlockImport, ParachainCandidate, ParachainConsensus, }; -use cumulus_client_network::build_block_announce_validator; +use cumulus_client_network::BlockAnnounceValidator; use cumulus_client_service::{ prepare_node_config, start_collator, start_full_node, StartCollatorParams, StartFullNodeParams, }; @@ -27,6 +26,8 @@ use cumulus_primitives_core::{ relay_chain::v1::{Hash as PHash, PersistedValidationData}, ParaId, }; +use cumulus_relay_chain_interface::RelayChainInterface; +use cumulus_relay_chain_local::build_relay_chain_interface; use polkadot_service::NativeExecutionDispatch; use crate::rpc; @@ -51,7 +52,7 @@ use sp_runtime::{ generic::BlockId, traits::{BlakeTwo256, Header as HeaderT}, }; -use std::sync::Arc; +use std::{sync::Arc, time::Duration}; use substrate_prometheus_endpoint::Registry; /// Native executor instance. @@ -84,6 +85,21 @@ impl sc_executor::NativeExecutionDispatch for ShellRuntimeExecutor { } } +/// Native executor instance. +pub struct SeedlingRuntimeExecutor; + +impl sc_executor::NativeExecutionDispatch for SeedlingRuntimeExecutor { + type ExtendHostFunctions = (); + + fn dispatch(method: &str, data: &[u8]) -> Option> { + seedling_runtime::api::dispatch(method, data) + } + + fn native_version() -> sc_executor::NativeVersion { + seedling_runtime::native_version() + } +} + // Native Statemint executor instance. pub struct StatemintRuntimeExecutor; @@ -196,6 +212,7 @@ where config.wasm_method, config.default_heap_pages, config.max_runtime_instances, + config.runtime_cache_size, ); let (client, backend, keystore_container, task_manager) = @@ -209,7 +226,7 @@ where let telemetry_worker_handle = telemetry.as_ref().map(|(worker, _)| worker.handle()); let telemetry = telemetry.map(|(worker, telemetry)| { - task_manager.spawn_handle().spawn("telemetry", worker.run()); + task_manager.spawn_handle().spawn("telemetry", None, worker.run()); telemetry }); @@ -295,7 +312,7 @@ where Option<&Registry>, Option, &TaskManager, - &polkadot_service::NewFull, + Arc, Arc< sc_transaction_pool::FullPool< Block, @@ -316,27 +333,24 @@ where let params = new_partial::(¶chain_config, build_import_queue)?; let (mut telemetry, telemetry_worker_handle) = params.other; - let relay_chain_full_node = - cumulus_client_service::build_polkadot_full_node(polkadot_config, telemetry_worker_handle) + 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, telemetry_worker_handle, &mut task_manager) .map_err(|e| match e { polkadot_service::Error::Sub(x) => x, s => format!("{}", s).into(), })?; - let client = params.client.clone(); - let backend = params.backend.clone(); - let block_announce_validator = build_block_announce_validator( - relay_chain_full_node.client.clone(), - id, - Box::new(relay_chain_full_node.network.clone()), - relay_chain_full_node.backend.clone(), - ); + let block_announce_validator = BlockAnnounceValidator::new(relay_chain_interface.clone(), id); let force_authoring = parachain_config.force_authoring; let validator = parachain_config.role.is_authority(); let prometheus_registry = parachain_config.prometheus_registry().cloned(); let transaction_pool = params.transaction_pool.clone(); - let mut task_manager = params.task_manager; let import_queue = cumulus_client_service::SharedImportQueue::new(params.import_queue); let (network, system_rpc_tx, start_network) = sc_service::build_network(sc_service::BuildNetworkParams { @@ -345,8 +359,9 @@ where transaction_pool: transaction_pool.clone(), spawn_handle: task_manager.spawn_handle(), import_queue: import_queue.clone(), - on_demand: None, - block_announce_validator_builder: Some(Box::new(|_| block_announce_validator)), + block_announce_validator_builder: Some(Box::new(|_| { + Box::new(block_announce_validator) + })), warp_sync: None, })?; @@ -354,8 +369,6 @@ where let rpc_extensions_builder = Box::new(move |_, _| rpc_ext_builder(rpc_client.clone())); sc_service::spawn_tasks(sc_service::SpawnTasksParams { - on_demand: None, - remote_blockchain: None, rpc_extensions_builder, client: client.clone(), transaction_pool: transaction_pool.clone(), @@ -379,7 +392,7 @@ where prometheus_registry.as_ref(), telemetry.as_ref().map(|t| t.handle()), &task_manager, - &relay_chain_full_node, + relay_chain_interface.clone(), transaction_pool, network, params.keystore_container.sync_keystore(), @@ -394,10 +407,12 @@ where announce_block, client: client.clone(), task_manager: &mut task_manager, - relay_chain_full_node, + relay_chain_interface, spawner, parachain_consensus, import_queue, + collator_key, + slot_duration: Duration::from_secs(6), }; start_collator(params).await?; @@ -407,7 +422,7 @@ where announce_block, task_manager: &mut task_manager, para_id: id, - relay_chain_full_node, + relay_chain_interface, }; start_full_node(params)?; @@ -473,7 +488,7 @@ where Option<&Registry>, Option, &TaskManager, - &polkadot_service::NewFull, + Arc, Arc< sc_transaction_pool::FullPool< Block, @@ -494,27 +509,23 @@ where let params = new_partial::(¶chain_config, build_import_queue)?; let (mut telemetry, telemetry_worker_handle) = params.other; - let relay_chain_full_node = - cumulus_client_service::build_polkadot_full_node(polkadot_config, telemetry_worker_handle) + 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, telemetry_worker_handle, &mut task_manager) .map_err(|e| match e { polkadot_service::Error::Sub(x) => x, s => format!("{}", s).into(), })?; - let client = params.client.clone(); - let backend = params.backend.clone(); - let block_announce_validator = build_block_announce_validator( - relay_chain_full_node.client.clone(), - id, - Box::new(relay_chain_full_node.network.clone()), - relay_chain_full_node.backend.clone(), - ); + let block_announce_validator = BlockAnnounceValidator::new(relay_chain_interface.clone(), id); let force_authoring = parachain_config.force_authoring; let validator = parachain_config.role.is_authority(); let prometheus_registry = parachain_config.prometheus_registry().cloned(); let transaction_pool = params.transaction_pool.clone(); - let mut task_manager = params.task_manager; let import_queue = cumulus_client_service::SharedImportQueue::new(params.import_queue); let (network, system_rpc_tx, start_network) = sc_service::build_network(sc_service::BuildNetworkParams { @@ -523,8 +534,9 @@ where transaction_pool: transaction_pool.clone(), spawn_handle: task_manager.spawn_handle(), import_queue: import_queue.clone(), - on_demand: None, - block_announce_validator_builder: Some(Box::new(|_| block_announce_validator)), + block_announce_validator_builder: Some(Box::new(|_| { + Box::new(block_announce_validator) + })), warp_sync: None, })?; @@ -544,8 +556,6 @@ where }; sc_service::spawn_tasks(sc_service::SpawnTasksParams { - on_demand: None, - remote_blockchain: None, rpc_extensions_builder, client: client.clone(), transaction_pool: transaction_pool.clone(), @@ -569,7 +579,7 @@ where prometheus_registry.as_ref(), telemetry.as_ref().map(|t| t.handle()), &task_manager, - &relay_chain_full_node, + relay_chain_interface.clone(), transaction_pool, network, params.keystore_container.sync_keystore(), @@ -584,10 +594,12 @@ where announce_block, client: client.clone(), task_manager: &mut task_manager, - relay_chain_full_node, + relay_chain_interface: relay_chain_interface.clone(), spawner, parachain_consensus, import_queue, + collator_key, + slot_duration: Duration::from_secs(6), }; start_collator(params).await?; @@ -597,7 +609,7 @@ where announce_block, task_manager: &mut task_manager, para_id: id, - relay_chain_full_node, + relay_chain_interface, }; start_full_node(params)?; @@ -688,7 +700,7 @@ pub async fn start_rococo_parachain_node( prometheus_registry, telemetry, task_manager, - relay_chain_node, + relay_chain_interface, transaction_pool, sync_oracle, keystore, @@ -703,9 +715,8 @@ pub async fn start_rococo_parachain_node( telemetry.clone(), ); - let relay_chain_backend = relay_chain_node.backend.clone(); - let relay_chain_client = relay_chain_node.client.clone(); - Ok(build_aura_consensus::< + + Ok(AuraConsensus::build::< sp_consensus_aura::sr25519::AuthorityPair, _, _, @@ -713,17 +724,13 @@ pub async fn start_rococo_parachain_node( _, _, _, - _, - _, - _, >(BuildAuraConsensusParams { proposer_factory, create_inherent_data_providers: move |_, (relay_parent, validation_data)| { let parachain_inherent = - cumulus_primitives_parachain_inherent::ParachainInherentData::create_at_with_client( + cumulus_primitives_parachain_inherent::ParachainInherentData::create_at( relay_parent, - &relay_chain_client, - &*relay_chain_backend, + &relay_chain_interface, &validation_data, id, ); @@ -745,8 +752,6 @@ pub async fn start_rococo_parachain_node( } }, block_import: client.clone(), - relay_chain_client: relay_chain_node.client.clone(), - relay_chain_backend: relay_chain_node.backend.clone(), para_client: client.clone(), backoff_authoring_blocks: Option::<()>::None, sync_oracle, @@ -765,20 +770,34 @@ pub async fn start_rococo_parachain_node( } /// Build the import queue for the shell runtime. -pub fn shell_build_import_queue( - client: Arc< - TFullClient>, - >, +pub fn shell_build_import_queue( + client: Arc>>, config: &Configuration, _: Option, task_manager: &TaskManager, ) -> Result< sc_consensus::DefaultImportQueue< Block, - TFullClient>, + TFullClient>, >, sc_service::Error, -> { +> +where + RuntimeApi: ConstructRuntimeApi>> + + Send + + Sync + + 'static, + RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue + + sp_api::Metadata + + sp_session::SessionKeys + + sp_api::ApiExt< + Block, + StateBackend = sc_client_api::StateBackendFor, Block>, + > + sp_offchain::OffchainWorkerApi + + sp_block_builder::BlockBuilder, + sc_client_api::StateBackendFor, Block>: sp_api::StateBackend, + Executor: sc_executor::NativeExecutionDispatch + 'static, +{ cumulus_client_consensus_relay_chain::import_queue( client.clone(), client, @@ -790,17 +809,32 @@ pub fn shell_build_import_queue( } /// Start a polkadot-shell parachain node. -pub async fn start_shell_node( +pub async fn start_shell_node( parachain_config: Configuration, polkadot_config: Configuration, id: ParaId, ) -> sc_service::error::Result<( TaskManager, - Arc< - TFullClient>, - >, -)> { - start_shell_node_impl::( + Arc>>, +)> +where + RuntimeApi: ConstructRuntimeApi>> + + Send + + Sync + + 'static, + RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue + + sp_api::Metadata + + sp_session::SessionKeys + + sp_api::ApiExt< + Block, + StateBackend = sc_client_api::StateBackendFor, Block>, + > + sp_offchain::OffchainWorkerApi + + sp_block_builder::BlockBuilder + + cumulus_primitives_core::CollectCollationInfo, + sc_client_api::StateBackendFor, Block>: sp_api::StateBackend, + Executor: sc_executor::NativeExecutionDispatch + 'static, +{ + start_shell_node_impl::( parachain_config, polkadot_config, id, @@ -810,7 +844,7 @@ pub async fn start_shell_node( prometheus_registry, telemetry, task_manager, - relay_chain_node, + relay_chain_interface, transaction_pool, _, _, @@ -823,25 +857,20 @@ pub async fn start_shell_node( telemetry.clone(), ); - let relay_chain_backend = relay_chain_node.backend.clone(); - let relay_chain_client = relay_chain_node.client.clone(); - Ok(cumulus_client_consensus_relay_chain::build_relay_chain_consensus( cumulus_client_consensus_relay_chain::BuildRelayChainConsensusParams { para_id: id, proposer_factory, block_import: client.clone(), - relay_chain_client: relay_chain_node.client.clone(), - relay_chain_backend: relay_chain_node.backend.clone(), + relay_chain_interface: relay_chain_interface.clone(), create_inherent_data_providers: move |_, (relay_parent, validation_data)| { let parachain_inherent = - cumulus_primitives_parachain_inherent::ParachainInherentData::create_at_with_client( - relay_parent, - &relay_chain_client, - &*relay_chain_backend, - &validation_data, - id, - ); + cumulus_primitives_parachain_inherent::ParachainInherentData::create_at( + relay_parent, + &relay_chain_interface, + &validation_data, + id, + ); async move { let parachain_inherent = parachain_inherent.ok_or_else(|| { Box::::from( @@ -1080,19 +1109,17 @@ where prometheus_registry, telemetry, task_manager, - relay_chain_node, + relay_chain_interface, transaction_pool, sync_oracle, keystore, force_authoring| { let client2 = client.clone(); - let relay_chain_backend = relay_chain_node.backend.clone(); - let relay_chain_client = relay_chain_node.client.clone(); let spawn_handle = task_manager.spawn_handle(); let transaction_pool2 = transaction_pool.clone(); let telemetry2 = telemetry.clone(); let prometheus_registry2 = prometheus_registry.map(|r| (*r).clone()); - + let relay_chain_for_aura = relay_chain_interface.clone(); let aura_consensus = BuildOnAccess::Uninitialized(Some(Box::new(move || { let slot_duration = cumulus_client_consensus_aura::slot_duration(&*client2).unwrap(); @@ -1105,63 +1132,51 @@ where telemetry2.clone(), ); - let relay_chain_backend2 = relay_chain_backend.clone(); - let relay_chain_client2 = relay_chain_client.clone(); + AuraConsensus::build::( + BuildAuraConsensusParams { + proposer_factory, + create_inherent_data_providers: + move |_, (relay_parent, validation_data)| { + let parachain_inherent = + cumulus_primitives_parachain_inherent::ParachainInherentData::create_at( + relay_parent, + &relay_chain_for_aura, + &validation_data, + id, + ); + async move { + let time = + sp_timestamp::InherentDataProvider::from_system_time(); - build_aura_consensus::< - sp_consensus_aura::sr25519::AuthorityPair, - _, - _, - _, - _, - _, - _, - _, - _, - _, - >(BuildAuraConsensusParams { - proposer_factory, - create_inherent_data_providers: move |_, (relay_parent, validation_data)| { - let parachain_inherent = - cumulus_primitives_parachain_inherent::ParachainInherentData::create_at_with_client( - relay_parent, - &relay_chain_client, - &*relay_chain_backend, - &validation_data, - id, - ); - async move { - let time = sp_timestamp::InherentDataProvider::from_system_time(); - - let slot = + let slot = sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_duration( *time, slot_duration.slot_duration(), ); - let parachain_inherent = parachain_inherent.ok_or_else(|| { - Box::::from( - "Failed to create parachain inherent", - ) - })?; - Ok((time, slot, parachain_inherent)) - } + let parachain_inherent = + parachain_inherent.ok_or_else(|| { + Box::::from( + "Failed to create parachain inherent", + ) + })?; + Ok((time, slot, parachain_inherent)) + } + }, + block_import: client2.clone(), + para_client: client2.clone(), + backoff_authoring_blocks: Option::<()>::None, + sync_oracle, + keystore, + force_authoring, + slot_duration, + // We got around 500ms for proposing + block_proposal_slot_portion: SlotProportion::new(1f32 / 24f32), + // And a maximum of 750ms if slots are skipped + max_block_proposal_slot_portion: Some(SlotProportion::new(1f32 / 16f32)), + telemetry: telemetry2, }, - block_import: client2.clone(), - relay_chain_client: relay_chain_client2, - relay_chain_backend: relay_chain_backend2, - para_client: client2.clone(), - backoff_authoring_blocks: Option::<()>::None, - sync_oracle, - keystore, - force_authoring, - slot_duration, - // We got around 500ms for proposing - block_proposal_slot_portion: SlotProportion::new(1f32 / 24f32), - // And a maximum of 750ms if slots are skipped - max_block_proposal_slot_portion: Some(SlotProportion::new(1f32 / 16f32)), - telemetry: telemetry2, - }) + ) }))); let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( @@ -1172,24 +1187,19 @@ where telemetry.clone(), ); - let relay_chain_backend = relay_chain_node.backend.clone(); - let relay_chain_client = relay_chain_node.client.clone(); - let relay_chain_consensus = cumulus_client_consensus_relay_chain::build_relay_chain_consensus( cumulus_client_consensus_relay_chain::BuildRelayChainConsensusParams { para_id: id, proposer_factory, block_import: client.clone(), - relay_chain_client: relay_chain_node.client.clone(), - relay_chain_backend: relay_chain_node.backend.clone(), + relay_chain_interface: relay_chain_interface.clone(), create_inherent_data_providers: move |_, (relay_parent, validation_data)| { let parachain_inherent = - cumulus_primitives_parachain_inherent::ParachainInherentData::create_at_with_client( + cumulus_primitives_parachain_inherent::ParachainInherentData::create_at( relay_parent, - &relay_chain_client, - &*relay_chain_backend, + &relay_chain_interface, &validation_data, id, ); diff --git a/polkadot-parachains/statemine/Cargo.toml b/polkadot-parachains/statemine/Cargo.toml index ce1b05faad..5f4166ac5e 100644 --- a/polkadot-parachains/statemine/Cargo.toml +++ b/polkadot-parachains/statemine/Cargo.toml @@ -1,17 +1,17 @@ [package] -name = 'statemine-runtime' -version = '2.0.0' +name = "statemine-runtime" +version = "2.0.0" authors = ["Parity Technologies "] -edition = '2018' +edition = "2021" description = "Kusama variant of Statemint parachain runtime" [dependencies] codec = { package = "parity-scale-codec", version = "2.3.0", default-features = false, features = ["derive", "max-encoded-len"] } -hex-literal = { version = '0.3.1', optional = true } +hex-literal = { version = "0.3.1", optional = true } log = { version = "0.4.14", default-features = false } parachain-info = { path = "../pallets/parachain-info", default-features = false } scale-info = { version = "1.0.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.101", optional = true, features = ["derive"] } +serde = { version = "1.0.132", optional = true, features = ["derive"] } smallvec = "1.6.1" # Substrate dependencies @@ -34,13 +34,13 @@ frame-support = { git = "https://github.com/paritytech/substrate", default-featu frame-executive = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } frame-system = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } frame-system-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } +pallet-asset-tx-payment = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-assets = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } pallet-aura = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } pallet-authorship = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } pallet-balances = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } pallet-multisig = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } pallet-proxy = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } -pallet-randomness-collective-flip = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } pallet-session = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } pallet-sudo = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } pallet-timestamp = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } @@ -62,7 +62,6 @@ cumulus-pallet-xcmp-queue = { path = "../../pallets/xcmp-queue", default-feature cumulus-pallet-xcm = { path = "../../pallets/xcm", default-features = false } cumulus-pallet-session-benchmarking = {path = "../../pallets/session-benchmarking", default-features = false, version = "3.0.0"} cumulus-ping = { path = "../pallets/ping", default-features = false } -pallet-asset-tx-payment = { path = "../../pallets/asset-tx-payment", default-features = false } pallet-collator-selection = { path = "../../pallets/collator-selection", default-features = false } parachains-common = { path = "../parachains-common", default-features = false } @@ -74,6 +73,9 @@ xcm-builder = { git = "https://github.com/paritytech/polkadot", default-features xcm-executor = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" } pallet-xcm = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" } +# Try-runtime stuff +frame-try-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, optional = true , branch = "master" } + [dev-dependencies] hex-literal = "0.3.1" @@ -83,23 +85,27 @@ substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", bran [features] default = [ "std" ] runtime-benchmarks = [ - 'hex-literal', - 'sp-runtime/runtime-benchmarks', - 'xcm-builder/runtime-benchmarks', - 'frame-benchmarking', - 'frame-system-benchmarking', - 'frame-support/runtime-benchmarks', - 'frame-system/runtime-benchmarks', - 'pallet-assets/runtime-benchmarks', - 'pallet-balances/runtime-benchmarks', - 'pallet-multisig/runtime-benchmarks', - 'pallet-proxy/runtime-benchmarks', - 'cumulus-pallet-session-benchmarking/runtime-benchmarks', - 'pallet-uniques/runtime-benchmarks', - 'pallet-utility/runtime-benchmarks', - 'pallet-timestamp/runtime-benchmarks', - 'pallet-xcm/runtime-benchmarks', - 'pallet-collator-selection/runtime-benchmarks', + "hex-literal", + "sp-runtime/runtime-benchmarks", + "xcm-builder/runtime-benchmarks", + "frame-benchmarking/runtime-benchmarks", + "frame-system-benchmarking", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-assets/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", + "pallet-multisig/runtime-benchmarks", + "pallet-proxy/runtime-benchmarks", + "cumulus-pallet-session-benchmarking/runtime-benchmarks", + "pallet-uniques/runtime-benchmarks", + "pallet-utility/runtime-benchmarks", + "pallet-timestamp/runtime-benchmarks", + "pallet-xcm/runtime-benchmarks", + "pallet-collator-selection/runtime-benchmarks", +] +try-runtime = [ + "frame-try-runtime", + "frame-executive/try-runtime", ] std = [ "codec/std", @@ -127,7 +133,6 @@ std = [ "pallet-balances/std", "pallet-multisig/std", "pallet-proxy/std", - "pallet-randomness-collective-flip/std", "pallet-session/std", "pallet-sudo/std", "pallet-timestamp/std", diff --git a/polkadot-parachains/statemine/src/lib.rs b/polkadot-parachains/statemine/src/lib.rs index d3d257056f..5b4cac3895 100644 --- a/polkadot-parachains/statemine/src/lib.rs +++ b/polkadot-parachains/statemine/src/lib.rs @@ -43,7 +43,7 @@ use codec::{Decode, Encode, MaxEncodedLen}; use constants::{currency::*, fee::WeightToFee}; use frame_support::{ construct_runtime, match_type, parameter_types, - traits::{Contains, Everything, InstanceFilter, Nothing}, + traits::{EnsureOneOf, Everything, InstanceFilter, Nothing, PalletInfoAccess}, weights::{ constants::{BlockExecutionWeight, ExtrinsicBaseWeight}, DispatchClass, IdentityFee, Weight, @@ -52,7 +52,7 @@ use frame_support::{ }; use frame_system::{ limits::{BlockLength, BlockWeights}, - EnsureOneOf, EnsureRoot, + EnsureRoot, }; pub use parachains_common as common; use parachains_common::{ @@ -70,12 +70,12 @@ use polkadot_parachain::primitives::Sibling; use polkadot_runtime_common::{BlockHashCount, RocksDbWeight, SlowAdjustingFeeUpdate}; use xcm::latest::prelude::*; use xcm_builder::{ - AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, - AsPrefixedGeneralIndex, ConvertedConcreteAssetId, CurrencyAdapter, EnsureXcmOrigin, - FixedWeightBounds, FungiblesAdapter, IsConcrete, LocationInverter, NativeAsset, - ParentAsSuperuser, ParentIsDefault, RelayChainAsNative, SiblingParachainAsNative, - SiblingParachainConvertsVia, SignedAccountId32AsNative, SovereignSignedViaLocation, - TakeWeightCredit, UsingComponents, + AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, + AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, AsPrefixedGeneralIndex, + ConvertedConcreteAssetId, CurrencyAdapter, EnsureXcmOrigin, FixedWeightBounds, + FungiblesAdapter, IsConcrete, LocationInverter, NativeAsset, ParentAsSuperuser, + ParentIsDefault, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, + SignedAccountId32AsNative, SovereignSignedViaLocation, TakeWeightCredit, UsingComponents, }; use xcm_executor::{traits::JustTry, Config, XcmExecutor}; @@ -90,10 +90,11 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("statemine"), impl_name: create_runtime_str!("statemine"), authoring_version: 1, - spec_version: 5, + spec_version: 600, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 3, + state_version: 0, }; /// The version information used to identify this runtime when compiled natively. @@ -127,16 +128,9 @@ parameter_types! { pub const SS58Prefix: u8 = 2; } -pub struct BaseFilter; -impl Contains for BaseFilter { - fn contains(_c: &Call) -> bool { - true - } -} - // Configure FRAME pallets to include in runtime. impl frame_system::Config for Runtime { - type BaseCallFilter = BaseFilter; + type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = RuntimeBlockWeights; type BlockLength = RuntimeBlockLength; type AccountId = AccountId; @@ -159,6 +153,7 @@ impl frame_system::Config for Runtime { type SystemWeightInfo = (); type SS58Prefix = SS58Prefix; type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { @@ -221,6 +216,7 @@ impl pallet_transaction_payment::Config for Runtime { parameter_types! { pub const AssetDeposit: Balance = UNITS; // 1 UNIT deposit to create asset + pub const AssetAccountDeposit: Balance = deposit(1, 16); pub const ApprovalDeposit: Balance = EXISTENTIAL_DEPOSIT; pub const AssetsStringLimit: u32 = 50; /// Key = 32 bytes, Value = 36 bytes (32+1+1+1+1) @@ -231,11 +227,8 @@ parameter_types! { } /// We allow root and the Relay Chain council to execute privileged asset operations. -pub type AssetsForceOrigin = EnsureOneOf< - AccountId, - EnsureRoot, - EnsureXcm>, ->; +pub type AssetsForceOrigin = + EnsureOneOf, EnsureXcm>>; impl pallet_assets::Config for Runtime { type Event = Event; @@ -251,34 +244,7 @@ impl pallet_assets::Config for Runtime { type Freezer = (); type Extra = (); type WeightInfo = weights::pallet_assets::WeightInfo; -} - -parameter_types! { - pub const ClassDeposit: Balance = UNITS; // 1 UNIT deposit to create asset class - pub const InstanceDeposit: Balance = UNITS / 100; // 1/100 UNIT deposit to create asset instance - pub const KeyLimit: u32 = 32; // Max 32 bytes per key - pub const ValueLimit: u32 = 64; // Max 64 bytes per value - pub const UniquesMetadataDepositBase: Balance = deposit(1, 129); - pub const AttributeDepositBase: Balance = deposit(1, 0); - pub const DepositPerByte: Balance = deposit(0, 1); - pub const UniquesStringLimit: u32 = 128; -} - -impl pallet_uniques::Config for Runtime { - type Event = Event; - type ClassId = u32; - type InstanceId = u32; - type Currency = Balances; - type ForceOrigin = AssetsForceOrigin; - type ClassDeposit = ClassDeposit; - type InstanceDeposit = InstanceDeposit; - type MetadataDepositBase = UniquesMetadataDepositBase; - type AttributeDepositBase = AttributeDepositBase; - type DepositPerByte = DepositPerByte; - type StringLimit = UniquesStringLimit; - type KeyLimit = KeyLimit; - type ValueLimit = ValueLimit; - type WeightInfo = weights::pallet_uniques::WeightInfo; + type AssetAccountDeposit = AssetAccountDeposit; } parameter_types! { @@ -302,6 +268,7 @@ impl pallet_multisig::Config for Runtime { impl pallet_utility::Config for Runtime { type Event = Event; type Call = Call; + type PalletsOrigin = OriginCaller; type WeightInfo = weights::pallet_utility::WeightInfo; } @@ -344,7 +311,7 @@ pub enum ProxyType { AssetOwner, /// Asset manager. Can execute calls related to asset management. AssetManager, - // Collator selection proxy. Can execute calls related to collator selection mechanism. + /// Collator selection proxy. Can execute calls related to collator selection mechanism. Collator, } impl Default for ProxyType { @@ -456,8 +423,6 @@ impl cumulus_pallet_parachain_system::Config for Runtime { type ReservedXcmpWeight = ReservedXcmpWeight; } -impl pallet_randomness_collective_flip::Config for Runtime {} - impl parachain_info::Config for Runtime {} impl cumulus_pallet_aura_ext::Config for Runtime {} @@ -468,6 +433,8 @@ parameter_types! { pub RelayChainOrigin: Origin = cumulus_pallet_xcm::Origin::Relay.into(); pub Ancestry: MultiLocation = Parachain(ParachainInfo::parachain_id().into()).into(); pub const Local: MultiLocation = Here.into(); + pub AssetsPalletLocation: MultiLocation = + PalletInstance(::index() as u8).into(); pub CheckingAccount: AccountId = PolkadotXcm::check_account(); } @@ -505,7 +472,7 @@ pub type FungiblesTransactor = FungiblesAdapter< ConvertedConcreteAssetId< AssetId, Balance, - AsPrefixedGeneralIndex, + AsPrefixedGeneralIndex, JustTry, >, // Convert an XCM MultiLocation into a local account id: @@ -529,7 +496,7 @@ pub type XcmOriginToTransactDispatchOrigin = ( // 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, - // Native converter for Relay-chain (Parent) location; will converts to a `Relay` origin when + // Native converter for Relay-chain (Parent) location; will convert to a `Relay` origin when // recognised. RelayChainAsNative, // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when @@ -558,19 +525,28 @@ match_type! { MultiLocation { parents: 1, interior: X1(Plurality { id: BodyId::Executive, .. }) } }; } +match_type! { + pub type ParentOrSiblings: impl Contains = { + MultiLocation { parents: 1, interior: Here } | + MultiLocation { parents: 1, interior: X1(_) } + }; +} pub type Barrier = ( TakeWeightCredit, AllowTopLevelPaidExecutionFrom, + // Parent and its exec plurality get free execution AllowUnpaidExecutionFrom, - // ^^^ Parent and its exec plurality get free execution + // Expected responses are OK. + AllowKnownQueryResponses, + // Subscriptions for version tracking are OK. + AllowSubscriptionsFrom, ); pub struct XcmConfig; impl Config for XcmConfig { type Call = Call; type XcmSender = XcmRouter; - // How to withdraw and deposit an asset. type AssetTransactor = AssetTransactors; type OriginConverter = XcmOriginToTransactDispatchOrigin; type IsReserve = NativeAsset; @@ -598,7 +574,7 @@ pub type LocalOriginToLocation = (); /// queues. pub type XcmRouter = ( // Two routers - use UMP to communicate with the relay chain: - cumulus_primitives_utility::ParentAsUmp, + cumulus_primitives_utility::ParentAsUmp, // ..and XCMP to communicate with the sibling chains. XcmpQueue, ); @@ -616,7 +592,6 @@ impl pallet_xcm::Config for Runtime { type LocationInverter = LocationInverter; type Origin = Origin; type Call = Call; - const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; } @@ -630,7 +605,8 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime { type Event = Event; type XcmExecutor = XcmExecutor; type ChannelInfo = ParachainSystem; - type VersionWrapper = (); + type VersionWrapper = PolkadotXcm; + type ExecuteOverweightOrigin = EnsureRoot; } impl cumulus_pallet_dmp_queue::Config for Runtime { @@ -674,11 +650,8 @@ parameter_types! { } /// We allow root and the Relay Chain council to execute privileged collator selection operations. -pub type CollatorSelectionUpdateOrigin = EnsureOneOf< - AccountId, - EnsureRoot, - EnsureXcm>, ->; +pub type CollatorSelectionUpdateOrigin = + EnsureOneOf, EnsureXcm>>; impl pallet_collator_selection::Config for Runtime { type Event = Event; @@ -704,6 +677,34 @@ impl pallet_asset_tx_payment::Config for Runtime { >; } +parameter_types! { + pub const ClassDeposit: Balance = UNITS; // 1 UNIT deposit to create asset class + pub const InstanceDeposit: Balance = UNITS / 100; // 1/100 UNIT deposit to create asset instance + pub const KeyLimit: u32 = 32; // Max 32 bytes per key + pub const ValueLimit: u32 = 64; // Max 64 bytes per value + pub const UniquesMetadataDepositBase: Balance = deposit(1, 129); + pub const AttributeDepositBase: Balance = deposit(1, 0); + pub const DepositPerByte: Balance = deposit(0, 1); + pub const UniquesStringLimit: u32 = 128; +} + +impl pallet_uniques::Config for Runtime { + type Event = Event; + type ClassId = u32; + type InstanceId = u32; + type Currency = Balances; + type ForceOrigin = AssetsForceOrigin; + type ClassDeposit = ClassDeposit; + type InstanceDeposit = InstanceDeposit; + type MetadataDepositBase = UniquesMetadataDepositBase; + type AttributeDepositBase = AttributeDepositBase; + type DepositPerByte = DepositPerByte; + type StringLimit = UniquesStringLimit; + type KeyLimit = KeyLimit; + type ValueLimit = ValueLimit; + type WeightInfo = weights::pallet_uniques::WeightInfo; +} + // Create the runtime by composing the FRAME pallets that were previously configured. construct_runtime!( pub enum Runtime where @@ -716,7 +717,7 @@ construct_runtime!( ParachainSystem: cumulus_pallet_parachain_system::{ Pallet, Call, Config, Storage, Inherent, Event, ValidateUnsigned, } = 1, - RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Pallet, Storage} = 2, + // RandomnessCollectiveFlip = 2 removed Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent} = 3, ParachainInfo: parachain_info::{Pallet, Storage, Config} = 4, @@ -725,7 +726,7 @@ construct_runtime!( TransactionPayment: pallet_transaction_payment::{Pallet, Storage} = 11, AssetTxPayment: pallet_asset_tx_payment::{Pallet} = 12, - // Collator support. the order of these 4 are important and shall not change. + // Collator support. the order of these 5 are important and shall not change. Authorship: pallet_authorship::{Pallet, Call, Storage} = 20, CollatorSelection: pallet_collator_selection::{Pallet, Call, Storage, Event, Config} = 21, Session: pallet_session::{Pallet, Call, Storage, Event, Config} = 22, @@ -734,7 +735,7 @@ construct_runtime!( // XCM helpers. XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event} = 30, - PolkadotXcm: pallet_xcm::{Pallet, Call, Event, Origin} = 31, + PolkadotXcm: pallet_xcm::{Pallet, Call, Storage, Event, Origin} = 31, CumulusXcm: cumulus_pallet_xcm::{Pallet, Event, Origin} = 32, DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event} = 33, @@ -743,7 +744,7 @@ construct_runtime!( Multisig: pallet_multisig::{Pallet, Call, Storage, Event} = 41, Proxy: pallet_proxy::{Pallet, Call, Storage, Event} = 42, - // The main stage. To include pallet-assets-freezer and pallet-uniques. + // The main stage. Assets: pallet_assets::{Pallet, Call, Storage, Event} = 50, Uniques: pallet_uniques::{Pallet, Call, Storage, Event} = 51, } @@ -759,6 +760,7 @@ pub type SignedBlock = generic::SignedBlock; pub type BlockId = generic::BlockId; /// The SignedExtension to the basic transaction logic. pub type SignedExtra = ( + frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, frame_system::CheckGenesis, @@ -777,10 +779,20 @@ pub type Executive = frame_executive::Executive< Block, frame_system::ChainContext, Runtime, - AllPallets, - (), + AllPalletsWithSystem, + RemoveCollectiveFlip, >; +pub struct RemoveCollectiveFlip; +impl frame_support::traits::OnRuntimeUpgrade for RemoveCollectiveFlip { + fn on_runtime_upgrade() -> Weight { + use frame_support::storage::migration; + // Remove the storage value `RandomMaterial` from removed pallet `RandomnessCollectiveFlip` + migration::remove_storage_prefix(b"RandomnessCollectiveFlip", b"RandomMaterial", b""); + ::DbWeight::get().writes(1) + } +} + impl_runtime_apis! { impl sp_consensus_aura::AuraApi for Runtime { fn slot_duration() -> sp_consensus_aura::SlotDuration { @@ -888,6 +900,19 @@ impl_runtime_apis! { } } + #[cfg(feature = "try-runtime")] + impl frame_try_runtime::TryRuntime for Runtime { + fn on_runtime_upgrade() -> (Weight, Weight) { + log::info!("try-runtime::on_runtime_upgrade statemine."); + let weight = Executive::try_runtime_upgrade().unwrap(); + (weight, RuntimeBlockWeights::get().max_block) + } + + fn execute_block_no_check(block: Block) -> Weight { + Executive::execute_block_no_check(block) + } + } + #[cfg(feature = "runtime-benchmarks")] impl frame_benchmarking::Benchmark for Runtime { fn benchmark_metadata(extra: bool) -> ( diff --git a/polkadot-parachains/statemine/src/weights/pallet_assets.rs b/polkadot-parachains/statemine/src/weights/pallet_assets.rs index 8510491fdc..10bedb8e57 100644 --- a/polkadot-parachains/statemine/src/weights/pallet_assets.rs +++ b/polkadot-parachains/statemine/src/weights/pallet_assets.rs @@ -1,11 +1,27 @@ -//! Autogenerated weights for pallet_assets +// Copyright 2021 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_assets` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-05-31, STEPS: `[50, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2021-10-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemine-dev"), DB CACHE: 128 // Executed Command: -// ./target/release/statemint +// ./target/release/polkadot-collator // benchmark // --chain=statemine-dev // --execution=wasm @@ -15,145 +31,197 @@ // --steps=50 // --repeat=20 // --raw -// --output=./runtime/statemine/src/weights/ +// --header=./file_header.txt +// --output=./polkadot-parachains/statemine/src/weights + +#![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; use sp_std::marker::PhantomData; -/// Weight functions for pallet_assets. +/// Weight functions for `pallet_assets`. pub struct WeightInfo(PhantomData); impl pallet_assets::WeightInfo for WeightInfo { + // Storage: Assets Asset (r:1 w:1) fn create() -> Weight { - (44_224_000 as Weight) + (41_413_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Assets Asset (r:1 w:1) fn force_create() -> Weight { - (22_533_000 as Weight) + (21_199_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - fn destroy(c: u32, s: u32, a: u32) -> Weight { + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Account (r:5002 w:5001) + // Storage: System Account (r:5000 w:5000) + // Storage: Assets Metadata (r:1 w:0) + // Storage: Assets Approvals (r:501 w:500) + fn destroy(c: u32, s: u32, a: u32, ) -> Weight { (0 as Weight) - // Standard Error: 37_000 - .saturating_add((21_529_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 37_000 - .saturating_add((28_905_000 as Weight).saturating_mul(s as Weight)) - // Standard Error: 377_000 - .saturating_add((3_745_000 as Weight).saturating_mul(a as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) + // Standard Error: 40_000 + .saturating_add((19_864_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 40_000 + .saturating_add((25_737_000 as Weight).saturating_mul(s as Weight)) + // Standard Error: 408_000 + .saturating_add((27_884_000 as Weight).saturating_mul(a as Weight)) + .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(c as Weight))) .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) + .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(a as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) .saturating_add(T::DbWeight::get().writes((2 as Weight).saturating_mul(c as Weight))) .saturating_add(T::DbWeight::get().writes((2 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(a as Weight))) } + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Account (r:1 w:1) fn mint() -> Weight { - (49_078_000 as Weight) + (47_351_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Account (r:1 w:1) fn burn() -> Weight { - (55_886_000 as Weight) + (53_970_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Account (r:2 w:2) + // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - (84_857_000 as Weight) + (81_681_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Account (r:2 w:2) + // Storage: System Account (r:1 w:1) fn transfer_keep_alive() -> Weight { - (71_330_000 as Weight) + (69_302_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Account (r:2 w:2) + // Storage: System Account (r:1 w:1) fn force_transfer() -> Weight { - (85_127_000 as Weight) + (81_972_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } + // Storage: Assets Asset (r:1 w:0) + // Storage: Assets Account (r:1 w:1) fn freeze() -> Weight { - (31_403_000 as Weight) + (32_099_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Assets Asset (r:1 w:0) + // Storage: Assets Account (r:1 w:1) fn thaw() -> Weight { - (31_250_000 as Weight) + (32_431_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Assets Asset (r:1 w:1) fn freeze_asset() -> Weight { - (22_097_000 as Weight) + (24_419_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Assets Asset (r:1 w:1) fn thaw_asset() -> Weight { - (22_245_000 as Weight) + (24_542_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Metadata (r:1 w:0) fn transfer_ownership() -> Weight { - (25_479_000 as Weight) + (27_113_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Assets Asset (r:1 w:1) fn set_team() -> Weight { - (22_271_000 as Weight) + (24_634_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - fn set_metadata(_n: u32, s: u32) -> Weight { - (50_315_000 as Weight) + // Storage: Assets Asset (r:1 w:0) + // Storage: Assets Metadata (r:1 w:1) + fn set_metadata(_n: u32, s: u32, ) -> Weight { + (49_434_000 as Weight) + // Standard Error: 7_000 + .saturating_add((19_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: Assets Asset (r:1 w:0) + // Storage: Assets Metadata (r:1 w:1) + fn clear_metadata() -> Weight { + (48_070_000 as Weight) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: Assets Asset (r:1 w:0) + // Storage: Assets Metadata (r:1 w:1) + fn force_set_metadata(_n: u32, s: u32, ) -> Weight { + (26_297_000 as Weight) // Standard Error: 0 .saturating_add((8_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - fn clear_metadata() -> Weight { - (48_134_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) - } - fn force_set_metadata(_n: u32, s: u32) -> Weight { - (25_933_000 as Weight) - // Standard Error: 0 - .saturating_add((7_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) - } + // Storage: Assets Asset (r:1 w:0) + // Storage: Assets Metadata (r:1 w:1) fn force_clear_metadata() -> Weight { - (49_243_000 as Weight) + (47_220_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Assets Asset (r:1 w:1) fn force_asset_status() -> Weight { - (22_305_000 as Weight) + (22_869_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Approvals (r:1 w:1) fn approve_transfer() -> Weight { - (48_885_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + (55_872_000 as Weight) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: Assets Approvals (r:1 w:1) + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Account (r:2 w:2) + // Storage: System Account (r:1 w:1) fn transfer_approved() -> Weight { - (108_026_000 as Weight) + (107_100_000 as Weight) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Approvals (r:1 w:1) fn cancel_approval() -> Weight { - (48_943_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) - } - fn force_cancel_approval() -> Weight { - (56_914_000 as Weight) + (56_307_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Approvals (r:1 w:1) + fn force_cancel_approval() -> Weight { + (58_691_000 as Weight) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } } diff --git a/polkadot-parachains/statemine/src/weights/pallet_balances.rs b/polkadot-parachains/statemine/src/weights/pallet_balances.rs index f28035b070..47bf231a8a 100644 --- a/polkadot-parachains/statemine/src/weights/pallet_balances.rs +++ b/polkadot-parachains/statemine/src/weights/pallet_balances.rs @@ -1,11 +1,27 @@ -//! Autogenerated weights for pallet_balances +// Copyright 2021 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_balances` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-05-31, STEPS: `[50, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2021-10-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemine-dev"), DB CACHE: 128 // Executed Command: -// ./target/release/statemint +// ./target/release/polkadot-collator // benchmark // --chain=statemine-dev // --execution=wasm @@ -15,50 +31,59 @@ // --steps=50 // --repeat=20 // --raw -// --output=./runtime/statemine/src/weights/ +// --header=./file_header.txt +// --output=./polkadot-parachains/statemine/src/weights + +#![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; use sp_std::marker::PhantomData; -/// Weight functions for pallet_balances. +/// Weight functions for `pallet_balances`. pub struct WeightInfo(PhantomData); impl pallet_balances::WeightInfo for WeightInfo { + // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - (79_381_000 as Weight) + (70_228_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: System Account (r:1 w:1) fn transfer_keep_alive() -> Weight { - (58_057_000 as Weight) + (53_444_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: System Account (r:1 w:1) fn set_balance_creating() -> Weight { - (28_834_000 as Weight) + (28_370_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: System Account (r:1 w:1) fn set_balance_killing() -> Weight { - (36_213_000 as Weight) + (34_938_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: System Account (r:2 w:2) fn force_transfer() -> Weight { - (78_526_000 as Weight) + (71_481_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) fn transfer_all() -> Weight { - (84_170_000 as Weight) + (66_297_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) fn force_unreserve() -> Weight { - (27_766_000 as Weight) + (26_751_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } diff --git a/polkadot-parachains/statemine/src/weights/pallet_collator_selection.rs b/polkadot-parachains/statemine/src/weights/pallet_collator_selection.rs index 7bfb0838ee..7a8a369c30 100644 --- a/polkadot-parachains/statemine/src/weights/pallet_collator_selection.rs +++ b/polkadot-parachains/statemine/src/weights/pallet_collator_selection.rs @@ -1,11 +1,27 @@ -//! Autogenerated weights for pallet_collator_selection +// Copyright 2021 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_collator_selection` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-05-31, STEPS: `[50, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2021-10-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemine-dev"), DB CACHE: 128 // Executed Command: -// ./target/release/statemint +// ./target/release/polkadot-collator // benchmark // --chain=statemine-dev // --execution=wasm @@ -15,57 +31,80 @@ // --steps=50 // --repeat=20 // --raw -// --output=./runtime/statemine/src/weights/ +// --header=./file_header.txt +// --output=./polkadot-parachains/statemine/src/weights + +#![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; use sp_std::marker::PhantomData; -/// Weight functions for pallet_collator_selection. +/// Weight functions for `pallet_collator_selection`. pub struct WeightInfo(PhantomData); impl pallet_collator_selection::WeightInfo for WeightInfo { - fn set_invulnerables(b: u32) -> Weight { - (18_481_000 as Weight) + // Storage: CollatorSelection Invulnerables (r:0 w:1) + fn set_invulnerables(b: u32, ) -> Weight { + (17_178_000 as Weight) // Standard Error: 0 - .saturating_add((67_000 as Weight).saturating_mul(b as Weight)) + .saturating_add((48_000 as Weight).saturating_mul(b as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: CollatorSelection DesiredCandidates (r:0 w:1) fn set_desired_candidates() -> Weight { - (16_376_000 as Weight).saturating_add(T::DbWeight::get().writes(1 as Weight)) + (15_237_000 as Weight) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: CollatorSelection CandidacyBond (r:0 w:1) fn set_candidacy_bond() -> Weight { - (17_031_000 as Weight).saturating_add(T::DbWeight::get().writes(1 as Weight)) + (15_968_000 as Weight) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - fn register_as_candidate(c: u32) -> Weight { - (72_345_000 as Weight) + // Storage: CollatorSelection Candidates (r:1 w:1) + // Storage: CollatorSelection DesiredCandidates (r:1 w:0) + // Storage: CollatorSelection Invulnerables (r:1 w:0) + // Storage: Session NextKeys (r:1 w:0) + // Storage: CollatorSelection CandidacyBond (r:1 w:0) + // Storage: CollatorSelection LastAuthoredBlock (r:0 w:1) + fn register_as_candidate(c: u32, ) -> Weight { + (69_104_000 as Weight) // Standard Error: 0 - .saturating_add((197_000 as Weight).saturating_mul(c as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add((154_000 as Weight).saturating_mul(c as Weight)) + .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } - fn leave_intent(c: u32) -> Weight { - (55_446_000 as Weight) - // Standard Error: 0 - .saturating_add((153_000 as Weight).saturating_mul(c as Weight)) + // Storage: CollatorSelection Candidates (r:1 w:1) + // Storage: CollatorSelection LastAuthoredBlock (r:0 w:1) + fn leave_intent(c: u32, ) -> Weight { + (65_460_000 as Weight) + // Standard Error: 1_000 + .saturating_add((209_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:2 w:2) + // Storage: System BlockWeight (r:1 w:1) + // Storage: CollatorSelection LastAuthoredBlock (r:0 w:1) fn note_author() -> Weight { - (71_828_000 as Weight) + (62_879_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } - fn new_session(r: u32, c: u32) -> Weight { + // Storage: CollatorSelection Candidates (r:1 w:1) + // Storage: CollatorSelection LastAuthoredBlock (r:1000 w:1) + // Storage: System Account (r:1 w:1) + // Storage: CollatorSelection Invulnerables (r:1 w:0) + // Storage: System BlockWeight (r:1 w:1) + fn new_session(r: u32, c: u32, ) -> Weight { (0 as Weight) - // Standard Error: 1_004_000 - .saturating_add((110_066_000 as Weight).saturating_mul(r as Weight)) - // Standard Error: 1_004_000 - .saturating_add((152_035_000 as Weight).saturating_mul(c as Weight)) - .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) + // Standard Error: 4_304_000 + .saturating_add((24_161_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 4_304_000 + .saturating_add((112_936_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(c as Weight))) - .saturating_add(T::DbWeight::get().writes((2 as Weight).saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes((2 as Weight).saturating_mul(c as Weight))) + .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(r as Weight))) + .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(c as Weight))) } } diff --git a/polkadot-parachains/statemine/src/weights/pallet_multisig.rs b/polkadot-parachains/statemine/src/weights/pallet_multisig.rs index 4c8aac7fee..15041061c2 100644 --- a/polkadot-parachains/statemine/src/weights/pallet_multisig.rs +++ b/polkadot-parachains/statemine/src/weights/pallet_multisig.rs @@ -1,11 +1,27 @@ -//! Autogenerated weights for pallet_multisig +// Copyright 2021 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_multisig` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-05-31, STEPS: `[50, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2021-10-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemine-dev"), DB CACHE: 128 // Executed Command: -// ./target/release/statemint +// ./target/release/polkadot-collator // benchmark // --chain=statemine-dev // --execution=wasm @@ -15,92 +31,115 @@ // --steps=50 // --repeat=20 // --raw -// --output=./runtime/statemine/src/weights/ +// --header=./file_header.txt +// --output=./polkadot-parachains/statemine/src/weights + +#![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; use sp_std::marker::PhantomData; -/// Weight functions for pallet_multisig. +/// Weight functions for `pallet_multisig`. pub struct WeightInfo(PhantomData); impl pallet_multisig::WeightInfo for WeightInfo { - fn as_multi_threshold_1(z: u32) -> Weight { - (15_911_000 as Weight) + fn as_multi_threshold_1(z: u32, ) -> Weight { + (20_620_000 as Weight) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(z as Weight)) } - fn as_multi_create(s: u32, z: u32) -> Weight { - (55_326_000 as Weight) + // Storage: Multisig Multisigs (r:1 w:1) + // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) + fn as_multi_create(s: u32, z: u32, ) -> Weight { + (51_332_000 as Weight) // Standard Error: 0 - .saturating_add((133_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((160_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 - .saturating_add((1_000 as Weight).saturating_mul(z as Weight)) + .saturating_add((2_000 as Weight).saturating_mul(z as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - fn as_multi_create_store(s: u32, z: u32) -> Weight { - (62_423_000 as Weight) + // Storage: Multisig Multisigs (r:1 w:1) + // Storage: Multisig Calls (r:1 w:1) + // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) + fn as_multi_create_store(s: u32, z: u32, ) -> Weight { + (57_557_000 as Weight) + // Standard Error: 1_000 + .saturating_add((161_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 - .saturating_add((133_000 as Weight).saturating_mul(s as Weight)) - // Standard Error: 0 - .saturating_add((3_000 as Weight).saturating_mul(z as Weight)) + .saturating_add((2_000 as Weight).saturating_mul(z as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } - fn as_multi_approve(s: u32, z: u32) -> Weight { - (32_430_000 as Weight) + // Storage: Multisig Multisigs (r:1 w:1) + fn as_multi_approve(s: u32, z: u32, ) -> Weight { + (32_292_000 as Weight) + // Standard Error: 1_000 + .saturating_add((157_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 - .saturating_add((148_000 as Weight).saturating_mul(s as Weight)) - // Standard Error: 0 - .saturating_add((1_000 as Weight).saturating_mul(z as Weight)) + .saturating_add((2_000 as Weight).saturating_mul(z as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - fn as_multi_approve_store(s: u32, z: u32) -> Weight { - (59_789_000 as Weight) - // Standard Error: 0 - .saturating_add((165_000 as Weight).saturating_mul(s as Weight)) + // Storage: Multisig Multisigs (r:1 w:1) + // Storage: Multisig Calls (r:1 w:1) + fn as_multi_approve_store(s: u32, z: u32, ) -> Weight { + (54_871_000 as Weight) + // Standard Error: 1_000 + .saturating_add((169_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 .saturating_add((3_000 as Weight).saturating_mul(z as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } - fn as_multi_complete(s: u32, z: u32) -> Weight { - (80_926_000 as Weight) + // Storage: Multisig Multisigs (r:1 w:1) + // Storage: Multisig Calls (r:1 w:1) + // Storage: System Account (r:1 w:1) + fn as_multi_complete(s: u32, z: u32, ) -> Weight { + (70_826_000 as Weight) + // Standard Error: 1_000 + .saturating_add((255_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 - .saturating_add((276_000 as Weight).saturating_mul(s as Weight)) - // Standard Error: 0 - .saturating_add((5_000 as Weight).saturating_mul(z as Weight)) + .saturating_add((4_000 as Weight).saturating_mul(z as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } - fn approve_as_multi_create(s: u32) -> Weight { - (54_860_000 as Weight) + // Storage: Multisig Multisigs (r:1 w:1) + // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) + fn approve_as_multi_create(s: u32, ) -> Weight { + (51_385_000 as Weight) // Standard Error: 0 - .saturating_add((134_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((160_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - fn approve_as_multi_approve(s: u32) -> Weight { - (31_924_000 as Weight) + // Storage: Multisig Multisigs (r:1 w:1) + // Storage: Multisig Calls (r:1 w:0) + fn approve_as_multi_approve(s: u32, ) -> Weight { + (30_929_000 as Weight) // Standard Error: 0 - .saturating_add((154_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((161_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - fn approve_as_multi_complete(s: u32) -> Weight { - (154_001_000 as Weight) - // Standard Error: 0 - .saturating_add((281_000 as Weight).saturating_mul(s as Weight)) + // Storage: Multisig Multisigs (r:1 w:1) + // Storage: Multisig Calls (r:1 w:1) + // Storage: System Account (r:1 w:1) + fn approve_as_multi_complete(s: u32, ) -> Weight { + (106_393_000 as Weight) + // Standard Error: 1_000 + .saturating_add((257_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } - fn cancel_as_multi(s: u32) -> Weight { - (103_770_000 as Weight) - // Standard Error: 0 - .saturating_add((130_000 as Weight).saturating_mul(s as Weight)) + // Storage: Multisig Multisigs (r:1 w:1) + // Storage: Multisig Calls (r:1 w:1) + fn cancel_as_multi(s: u32, ) -> Weight { + (82_660_000 as Weight) + // Standard Error: 1_000 + .saturating_add((155_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } diff --git a/polkadot-parachains/statemine/src/weights/pallet_proxy.rs b/polkadot-parachains/statemine/src/weights/pallet_proxy.rs index da0a277769..48d799b1fc 100644 --- a/polkadot-parachains/statemine/src/weights/pallet_proxy.rs +++ b/polkadot-parachains/statemine/src/weights/pallet_proxy.rs @@ -1,11 +1,27 @@ -//! Autogenerated weights for pallet_proxy +// Copyright 2021 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 3.0.0 -//! DATE: 2021-05-31, STEPS: `[50, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2021-10-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemine-dev"), DB CACHE: 128 // Executed Command: -// ./target/release/statemint +// ./target/release/polkadot-collator // benchmark // --chain=statemine-dev // --execution=wasm @@ -15,91 +31,111 @@ // --steps=50 // --repeat=20 // --raw -// --output=./runtime/statemine/src/weights/ +// --header=./file_header.txt +// --output=./polkadot-parachains/statemine/src/weights + +#![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; use sp_std::marker::PhantomData; -/// Weight functions for pallet_proxy. +/// Weight functions for `pallet_proxy`. pub struct WeightInfo(PhantomData); impl pallet_proxy::WeightInfo for WeightInfo { - fn proxy(p: u32) -> Weight { - (27_318_000 as Weight) - // Standard Error: 1_000 - .saturating_add((208_000 as Weight).saturating_mul(p as Weight)) + // Storage: Proxy Proxies (r:1 w:0) + fn proxy(p: u32, ) -> Weight { + (23_732_000 as Weight) + // Standard Error: 2_000 + .saturating_add((136_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) } - fn proxy_announced(a: u32, p: u32) -> Weight { - (60_665_000 as Weight) + // Storage: Proxy Proxies (r:1 w:0) + // Storage: Proxy Announcements (r:1 w:1) + // Storage: System Account (r:1 w:1) + fn proxy_announced(a: u32, p: u32, ) -> Weight { + (53_185_000 as Weight) // Standard Error: 2_000 - .saturating_add((677_000 as Weight).saturating_mul(a as Weight)) + .saturating_add((486_000 as Weight).saturating_mul(a as Weight)) // Standard Error: 2_000 - .saturating_add((197_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((144_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } - fn remove_announcement(a: u32, p: u32) -> Weight { - (39_455_000 as Weight) + // Storage: Proxy Announcements (r:1 w:1) + // Storage: System Account (r:1 w:1) + fn remove_announcement(a: u32, p: u32, ) -> Weight { + (35_863_000 as Weight) // Standard Error: 2_000 - .saturating_add((687_000 as Weight).saturating_mul(a as Weight)) + .saturating_add((499_000 as Weight).saturating_mul(a as Weight)) // Standard Error: 2_000 - .saturating_add((3_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((12_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } - fn reject_announcement(a: u32, p: u32) -> Weight { - (39_411_000 as Weight) + // Storage: Proxy Announcements (r:1 w:1) + // Storage: System Account (r:1 w:1) + fn reject_announcement(a: u32, p: u32, ) -> Weight { + (35_723_000 as Weight) + // Standard Error: 1_000 + .saturating_add((500_000 as Weight).saturating_mul(a as Weight)) // Standard Error: 2_000 - .saturating_add((686_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 2_000 - .saturating_add((3_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((19_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } - fn announce(a: u32, p: u32) -> Weight { - (54_386_000 as Weight) + // Storage: Proxy Proxies (r:1 w:0) + // Storage: Proxy Announcements (r:1 w:1) + // Storage: System Account (r:1 w:1) + fn announce(a: u32, p: u32, ) -> Weight { + (50_128_000 as Weight) // Standard Error: 2_000 - .saturating_add((677_000 as Weight).saturating_mul(a as Weight)) + .saturating_add((481_000 as Weight).saturating_mul(a as Weight)) // Standard Error: 2_000 - .saturating_add((194_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((141_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } - fn add_proxy(p: u32) -> Weight { - (37_411_000 as Weight) + // Storage: Proxy Proxies (r:1 w:1) + fn add_proxy(p: u32, ) -> Weight { + (42_805_000 as Weight) + // Standard Error: 4_000 + .saturating_add((173_000 as Weight).saturating_mul(p as Weight)) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: Proxy Proxies (r:1 w:1) + fn remove_proxy(p: u32, ) -> Weight { + (34_597_000 as Weight) + // Standard Error: 4_000 + .saturating_add((218_000 as Weight).saturating_mul(p as Weight)) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: Proxy Proxies (r:1 w:1) + fn remove_proxies(p: u32, ) -> Weight { + (33_968_000 as Weight) // Standard Error: 2_000 - .saturating_add((298_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((121_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - fn remove_proxy(p: u32) -> Weight { - (36_658_000 as Weight) - // Standard Error: 2_000 - .saturating_add((332_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) - } - fn remove_proxies(p: u32) -> Weight { - (34_893_000 as Weight) - // Standard Error: 1_000 - .saturating_add((209_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) - } - fn anonymous(p: u32) -> Weight { - (51_243_000 as Weight) - // Standard Error: 1_000 - .saturating_add((44_000 as Weight).saturating_mul(p as Weight)) + // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) + // Storage: Proxy Proxies (r:1 w:1) + fn anonymous(p: u32, ) -> Weight { + (48_471_000 as Weight) + // Standard Error: 3_000 + .saturating_add((5_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - fn kill_anonymous(p: u32) -> Weight { - (37_188_000 as Weight) - // Standard Error: 1_000 - .saturating_add((208_000 as Weight).saturating_mul(p as Weight)) + // Storage: Proxy Proxies (r:1 w:1) + fn kill_anonymous(p: u32, ) -> Weight { + (35_705_000 as Weight) + // Standard Error: 2_000 + .saturating_add((127_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } diff --git a/polkadot-parachains/statemine/src/weights/pallet_session.rs b/polkadot-parachains/statemine/src/weights/pallet_session.rs index 2125bb0565..286b2c5047 100644 --- a/polkadot-parachains/statemine/src/weights/pallet_session.rs +++ b/polkadot-parachains/statemine/src/weights/pallet_session.rs @@ -1,7 +1,23 @@ -//! Autogenerated weights for pallet_session +// Copyright 2021 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_session` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-06-08, STEPS: `[50, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2021-10-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemine-dev"), DB CACHE: 128 // Executed Command: @@ -15,24 +31,31 @@ // --steps=50 // --repeat=20 // --raw -// --output=./polkadot-parachains/statemine-runtime/src/weights +// --header=./file_header.txt +// --output=./polkadot-parachains/statemine/src/weights + +#![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; use sp_std::marker::PhantomData; -/// Weight functions for pallet_session. +/// Weight functions for `pallet_session`. pub struct WeightInfo(PhantomData); impl pallet_session::WeightInfo for WeightInfo { + // Storage: Session NextKeys (r:1 w:1) + // Storage: Session KeyOwner (r:1 w:1) fn set_keys() -> Weight { - (25_201_000 as Weight) + (25_618_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: Session NextKeys (r:1 w:1) + // Storage: Session KeyOwner (r:0 w:1) fn purge_keys() -> Weight { - (17_510_000 as Weight) + (18_073_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } diff --git a/polkadot-parachains/statemine/src/weights/pallet_timestamp.rs b/polkadot-parachains/statemine/src/weights/pallet_timestamp.rs index f6cf6a9594..2c09955238 100644 --- a/polkadot-parachains/statemine/src/weights/pallet_timestamp.rs +++ b/polkadot-parachains/statemine/src/weights/pallet_timestamp.rs @@ -1,11 +1,27 @@ -//! Autogenerated weights for pallet_timestamp +// Copyright 2021 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_timestamp` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-05-31, STEPS: `[50, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2021-10-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemine-dev"), DB CACHE: 128 // Executed Command: -// ./target/release/statemint +// ./target/release/polkadot-collator // benchmark // --chain=statemine-dev // --execution=wasm @@ -15,23 +31,27 @@ // --steps=50 // --repeat=20 // --raw -// --output=./runtime/statemine/src/weights/ +// --header=./file_header.txt +// --output=./polkadot-parachains/statemine/src/weights + +#![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; use sp_std::marker::PhantomData; -/// Weight functions for pallet_timestamp. +/// Weight functions for `pallet_timestamp`. pub struct WeightInfo(PhantomData); impl pallet_timestamp::WeightInfo for WeightInfo { + // Storage: Timestamp Now (r:1 w:1) fn set() -> Weight { - (7_543_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) + (7_266_000 as Weight) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn on_finalize() -> Weight { - (4_272_000 as Weight) + (4_313_000 as Weight) } } diff --git a/polkadot-parachains/statemine/src/weights/pallet_uniques.rs b/polkadot-parachains/statemine/src/weights/pallet_uniques.rs index 1b42c35be2..c21abb8c6f 100644 --- a/polkadot-parachains/statemine/src/weights/pallet_uniques.rs +++ b/polkadot-parachains/statemine/src/weights/pallet_uniques.rs @@ -14,53 +14,63 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -//! Autogenerated weights for pallet_uniques +//! Autogenerated weights for `pallet_uniques` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-06-02, STEPS: `[50, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2021-10-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemine-dev"), DB CACHE: 128 // Executed Command: // ./target/release/polkadot-collator // benchmark // --chain=statemine-dev -// --steps=50 -// --repeat=20 -// --pallet=pallet_uniques -// --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 +// --pallet=pallet_uniques +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --raw // --header=./file_header.txt -// --output=./polkadot-parachains/statemine-runtime/src/weights/ +// --output=./polkadot-parachains/statemine/src/weights + +#![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; use sp_std::marker::PhantomData; -/// Weight functions for pallet_uniques. +/// Weight functions for `pallet_uniques`. pub struct WeightInfo(PhantomData); impl pallet_uniques::WeightInfo for WeightInfo { + // Storage: Uniques Class (r:1 w:1) fn create() -> Weight { - (42_199_000 as Weight) + (42_699_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Uniques Class (r:1 w:1) fn force_create() -> Weight { - (21_030_000 as Weight) + (21_910_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - fn destroy(n: u32, m: u32, a: u32) -> Weight { + // Storage: Uniques Class (r:1 w:1) + // Storage: Uniques Asset (r:1 w:0) + // Storage: Uniques Attribute (r:0 w:1000) + // Storage: Uniques ClassMetadataOf (r:0 w:1) + // Storage: Uniques InstanceMetadataOf (r:0 w:1000) + // Storage: Uniques Account (r:0 w:20) + fn destroy(n: u32, m: u32, a: u32, ) -> Weight { (0 as Weight) // Standard Error: 14_000 - .saturating_add((16_814_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((15_871_000 as Weight).saturating_mul(n as Weight)) // Standard Error: 14_000 - .saturating_add((1_026_000 as Weight).saturating_mul(m as Weight)) + .saturating_add((1_090_000 as Weight).saturating_mul(m as Weight)) // Standard Error: 14_000 - .saturating_add((952_000 as Weight).saturating_mul(a as Weight)) + .saturating_add((949_000 as Weight).saturating_mul(a as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -68,102 +78,141 @@ impl pallet_uniques::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(m as Weight))) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(a as Weight))) } + // Storage: Uniques Asset (r:1 w:1) + // Storage: Uniques Class (r:1 w:1) + // Storage: Uniques Account (r:0 w:1) fn mint() -> Weight { - (57_236_000 as Weight) + (55_650_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } + // Storage: Uniques Class (r:1 w:1) + // Storage: Uniques Asset (r:1 w:1) + // Storage: Uniques Account (r:0 w:1) fn burn() -> Weight { - (58_129_000 as Weight) + (57_692_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } + // Storage: Uniques Class (r:1 w:0) + // Storage: Uniques Asset (r:1 w:1) + // Storage: Uniques Account (r:0 w:2) fn transfer() -> Weight { - (42_980_000 as Weight) + (43_046_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } - fn redeposit(i: u32) -> Weight { + // Storage: Uniques Class (r:1 w:1) + // Storage: Uniques Asset (r:100 w:100) + fn redeposit(i: u32, ) -> Weight { (0 as Weight) // Standard Error: 11_000 - .saturating_add((26_921_000 as Weight).saturating_mul(i as Weight)) + .saturating_add((24_886_000 as Weight).saturating_mul(i as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(i as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) } + // Storage: Uniques Asset (r:1 w:1) + // Storage: Uniques Class (r:1 w:0) fn freeze() -> Weight { - (30_427_000 as Weight) + (30_115_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Uniques Asset (r:1 w:1) + // Storage: Uniques Class (r:1 w:0) fn thaw() -> Weight { - (29_789_000 as Weight) + (29_713_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Uniques Class (r:1 w:1) fn freeze_class() -> Weight { - (21_380_000 as Weight) + (22_174_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Uniques Class (r:1 w:1) fn thaw_class() -> Weight { - (21_430_000 as Weight) + (22_642_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Uniques Class (r:1 w:1) + // Storage: System Account (r:1 w:1) fn transfer_ownership() -> Weight { - (49_331_000 as Weight) + (49_489_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: Uniques Class (r:1 w:1) fn set_team() -> Weight { - (22_305_000 as Weight) + (23_260_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Uniques Class (r:1 w:1) fn force_asset_status() -> Weight { - (21_965_000 as Weight) + (22_727_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Uniques Class (r:1 w:1) + // Storage: Uniques InstanceMetadataOf (r:1 w:0) + // Storage: Uniques Attribute (r:1 w:1) fn set_attribute() -> Weight { - (70_386_000 as Weight) + (69_341_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: Uniques Class (r:1 w:1) + // Storage: Uniques InstanceMetadataOf (r:1 w:0) + // Storage: Uniques Attribute (r:1 w:1) fn clear_attribute() -> Weight { - (63_932_000 as Weight) + (63_758_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: Uniques Class (r:1 w:1) + // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn set_metadata() -> Weight { - (53_647_000 as Weight) + (53_201_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: Uniques Class (r:1 w:1) + // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn clear_metadata() -> Weight { - (52_353_000 as Weight) + (51_969_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: Uniques Class (r:1 w:1) + // Storage: Uniques ClassMetadataOf (r:1 w:1) fn set_class_metadata() -> Weight { - (51_900_000 as Weight) + (52_060_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: Uniques Class (r:1 w:0) + // Storage: Uniques ClassMetadataOf (r:1 w:1) fn clear_class_metadata() -> Weight { - (46_929_000 as Weight) + (47_464_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Uniques Class (r:1 w:0) + // Storage: Uniques Asset (r:1 w:1) fn approve_transfer() -> Weight { - (32_693_000 as Weight) + (32_921_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Uniques Class (r:1 w:0) + // Storage: Uniques Asset (r:1 w:1) fn cancel_approval() -> Weight { - (32_418_000 as Weight) + (32_538_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } diff --git a/polkadot-parachains/statemine/src/weights/pallet_utility.rs b/polkadot-parachains/statemine/src/weights/pallet_utility.rs index 17a2199707..3948438da8 100644 --- a/polkadot-parachains/statemine/src/weights/pallet_utility.rs +++ b/polkadot-parachains/statemine/src/weights/pallet_utility.rs @@ -1,11 +1,27 @@ -//! Autogenerated weights for pallet_utility +// Copyright 2021 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_utility` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-05-31, STEPS: `[50, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2021-10-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemine-dev"), DB CACHE: 128 // Executed Command: -// ./target/release/statemint +// ./target/release/polkadot-collator // benchmark // --chain=statemine-dev // --execution=wasm @@ -15,28 +31,34 @@ // --steps=50 // --repeat=20 // --raw -// --output=./runtime/statemine/src/weights/ +// --header=./file_header.txt +// --output=./polkadot-parachains/statemine/src/weights + +#![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; use sp_std::marker::PhantomData; -/// Weight functions for pallet_utility. +/// Weight functions for `pallet_utility`. pub struct WeightInfo(PhantomData); impl pallet_utility::WeightInfo for WeightInfo { - fn batch(c: u32) -> Weight { - (16_177_000 as Weight) - // Standard Error: 0 - .saturating_add((4_582_000 as Weight).saturating_mul(c as Weight)) + fn batch(c: u32, ) -> Weight { + (32_696_000 as Weight) + // Standard Error: 3_000 + .saturating_add((7_071_000 as Weight).saturating_mul(c as Weight)) } fn as_derivative() -> Weight { - (7_848_000 as Weight) + (5_201_000 as Weight) } - fn batch_all(c: u32) -> Weight { - (17_745_000 as Weight) - // Standard Error: 0 - .saturating_add((4_578_000 as Weight).saturating_mul(c as Weight)) + fn batch_all(c: u32, ) -> Weight { + (24_556_000 as Weight) + // Standard Error: 3_000 + .saturating_add((7_719_000 as Weight).saturating_mul(c as Weight)) + } + fn dispatch_as() -> Weight { + (14_340_000 as Weight) } } diff --git a/polkadot-parachains/statemint/Cargo.toml b/polkadot-parachains/statemint/Cargo.toml index 58b3e826c0..93ed0d4415 100644 --- a/polkadot-parachains/statemint/Cargo.toml +++ b/polkadot-parachains/statemint/Cargo.toml @@ -1,16 +1,16 @@ [package] -name = 'statemint-runtime' -version = '1.0.0' +name = "statemint-runtime" +version = "1.0.0" authors = ["Parity Technologies "] -edition = '2018' +edition = "2021" description = "Statemint parachain runtime" [dependencies] codec = { package = "parity-scale-codec", version = "2.3.0", default-features = false, features = ["derive", "max-encoded-len"] } -hex-literal = { version = '0.3.1', optional = true } +hex-literal = { version = "0.3.1", optional = true } log = { version = "0.4.14", default-features = false } parachain-info = { path = "../pallets/parachain-info", default-features = false } -serde = { version = "1.0.101", optional = true, features = ["derive"] } +serde = { version = "1.0.132", optional = true, features = ["derive"] } scale-info = { version = "1.0.0", default-features = false, features = ["derive"] } smallvec = "1.6.1" @@ -34,13 +34,13 @@ frame-support = { git = "https://github.com/paritytech/substrate", default-featu frame-executive = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } frame-system = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } frame-system-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } +pallet-asset-tx-payment = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-assets = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } pallet-aura = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } pallet-authorship = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } pallet-balances = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } pallet-multisig = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } pallet-proxy = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } -pallet-randomness-collective-flip = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } pallet-session = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } pallet-sudo = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } pallet-timestamp = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } @@ -62,7 +62,6 @@ cumulus-pallet-xcmp-queue = { path = "../../pallets/xcmp-queue", default-feature cumulus-pallet-xcm = { path = "../../pallets/xcm", default-features = false } cumulus-pallet-session-benchmarking = { path = "../../pallets/session-benchmarking", default-features = false, version = "3.0.0" } cumulus-ping = { path = "../pallets/ping", default-features = false } -pallet-asset-tx-payment = { path = "../../pallets/asset-tx-payment", default-features = false } pallet-collator-selection = { path = "../../pallets/collator-selection", default-features = false } parachains-common = { path = "../parachains-common", default-features = false } @@ -74,6 +73,9 @@ xcm-builder = { git = "https://github.com/paritytech/polkadot", default-features xcm-executor = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" } pallet-xcm = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" } +# Try-runtime stuff +frame-try-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, optional = true , branch = "master" } + [dev-dependencies] hex-literal = "0.3.1" @@ -83,23 +85,27 @@ substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", bran [features] default = [ "std" ] runtime-benchmarks = [ - 'cumulus-pallet-session-benchmarking/runtime-benchmarks', - 'hex-literal', - 'sp-runtime/runtime-benchmarks', - 'xcm-builder/runtime-benchmarks', - 'frame-benchmarking', - 'frame-system-benchmarking', - 'frame-support/runtime-benchmarks', - 'frame-system/runtime-benchmarks', - 'pallet-assets/runtime-benchmarks', - 'pallet-balances/runtime-benchmarks', - 'pallet-multisig/runtime-benchmarks', - 'pallet-proxy/runtime-benchmarks', - 'pallet-uniques/runtime-benchmarks', - 'pallet-utility/runtime-benchmarks', - 'pallet-timestamp/runtime-benchmarks', - 'pallet-xcm/runtime-benchmarks', - 'pallet-collator-selection/runtime-benchmarks', + "cumulus-pallet-session-benchmarking/runtime-benchmarks", + "hex-literal", + "sp-runtime/runtime-benchmarks", + "xcm-builder/runtime-benchmarks", + "frame-benchmarking/runtime-benchmarks", + "frame-system-benchmarking", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-assets/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", + "pallet-multisig/runtime-benchmarks", + "pallet-proxy/runtime-benchmarks", + "pallet-uniques/runtime-benchmarks", + "pallet-utility/runtime-benchmarks", + "pallet-timestamp/runtime-benchmarks", + "pallet-xcm/runtime-benchmarks", + "pallet-collator-selection/runtime-benchmarks", +] +try-runtime = [ + "frame-try-runtime", + "frame-executive/try-runtime", ] std = [ "codec/std", @@ -127,7 +133,6 @@ std = [ "pallet-balances/std", "pallet-multisig/std", "pallet-proxy/std", - "pallet-randomness-collective-flip/std", "pallet-session/std", "pallet-sudo/std", "pallet-timestamp/std", diff --git a/polkadot-parachains/statemint/src/lib.rs b/polkadot-parachains/statemint/src/lib.rs index b4e99ece7f..471fcf3c1b 100644 --- a/polkadot-parachains/statemint/src/lib.rs +++ b/polkadot-parachains/statemint/src/lib.rs @@ -43,7 +43,7 @@ use codec::{Decode, Encode, MaxEncodedLen}; use constants::{currency::*, fee::WeightToFee}; use frame_support::{ construct_runtime, match_type, parameter_types, - traits::{Contains, Everything, InstanceFilter, Nothing}, + traits::{Contains, EnsureOneOf, Everything, InstanceFilter, Nothing, PalletInfoAccess}, weights::{ constants::{BlockExecutionWeight, ExtrinsicBaseWeight}, DispatchClass, IdentityFee, Weight, @@ -52,7 +52,7 @@ use frame_support::{ }; use frame_system::{ limits::{BlockLength, BlockWeights}, - EnsureOneOf, EnsureRoot, + EnsureRoot, }; pub use parachains_common as common; use parachains_common::{ @@ -70,12 +70,12 @@ use polkadot_parachain::primitives::Sibling; use polkadot_runtime_common::{BlockHashCount, RocksDbWeight, SlowAdjustingFeeUpdate}; use xcm::latest::prelude::*; use xcm_builder::{ - AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, - AsPrefixedGeneralIndex, ConvertedConcreteAssetId, CurrencyAdapter, EnsureXcmOrigin, - FixedWeightBounds, FungiblesAdapter, IsConcrete, LocationInverter, NativeAsset, - ParentAsSuperuser, ParentIsDefault, RelayChainAsNative, SiblingParachainAsNative, - SiblingParachainConvertsVia, SignedAccountId32AsNative, SovereignSignedViaLocation, - TakeWeightCredit, UsingComponents, + AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, + AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, AsPrefixedGeneralIndex, + ConvertedConcreteAssetId, CurrencyAdapter, EnsureXcmOrigin, FixedWeightBounds, + FungiblesAdapter, IsConcrete, LocationInverter, NativeAsset, ParentAsSuperuser, + ParentIsDefault, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, + SignedAccountId32AsNative, SovereignSignedViaLocation, TakeWeightCredit, UsingComponents, }; use xcm_executor::{traits::JustTry, Config, XcmExecutor}; @@ -90,10 +90,11 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("statemint"), impl_name: create_runtime_str!("statemint"), authoring_version: 1, - spec_version: 100, + spec_version: 600, impl_version: 0, apis: RUNTIME_API_VERSIONS, - transaction_version: 2, + transaction_version: 3, + state_version: 0, }; /// The version information used to identify this runtime when compiled natively. @@ -164,6 +165,7 @@ impl frame_system::Config for Runtime { type SystemWeightInfo = (); type SS58Prefix = SS58Prefix; type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { @@ -224,10 +226,9 @@ impl pallet_transaction_payment::Config for Runtime { type OperationalFeeMultiplier = OperationalFeeMultiplier; } -impl pallet_randomness_collective_flip::Config for Runtime {} - parameter_types! { pub const AssetDeposit: Balance = 100 * DOLLARS; // 100 DOLLARS deposit to create asset + pub const AssetAccountDeposit: Balance = deposit(1, 16); pub const ApprovalDeposit: Balance = EXISTENTIAL_DEPOSIT; pub const AssetsStringLimit: u32 = 50; /// Key = 32 bytes, Value = 36 bytes (32+1+1+1+1) @@ -238,11 +239,8 @@ parameter_types! { } /// We allow root and the Relay Chain council to execute privileged asset operations. -pub type AssetsForceOrigin = EnsureOneOf< - AccountId, - EnsureRoot, - EnsureXcm>, ->; +pub type AssetsForceOrigin = + EnsureOneOf, EnsureXcm>>; impl pallet_assets::Config for Runtime { type Event = Event; @@ -258,6 +256,7 @@ impl pallet_assets::Config for Runtime { type Freezer = (); type Extra = (); type WeightInfo = weights::pallet_assets::WeightInfo; + type AssetAccountDeposit = AssetAccountDeposit; } parameter_types! { @@ -281,6 +280,7 @@ impl pallet_multisig::Config for Runtime { impl pallet_utility::Config for Runtime { type Event = Event; type Call = Call; + type PalletsOrigin = OriginCaller; type WeightInfo = weights::pallet_utility::WeightInfo; } @@ -323,7 +323,7 @@ pub enum ProxyType { AssetOwner, /// Asset manager. Can execute calls related to asset management. AssetManager, - // Collator selection proxy. Can execute calls related to collator selection mechanism. + /// Collator selection proxy. Can execute calls related to collator selection mechanism. Collator, } impl Default for ProxyType { @@ -445,6 +445,8 @@ parameter_types! { pub RelayChainOrigin: Origin = cumulus_pallet_xcm::Origin::Relay.into(); pub Ancestry: MultiLocation = Parachain(ParachainInfo::parachain_id().into()).into(); pub const Local: MultiLocation = Here.into(); + pub AssetsPalletLocation: MultiLocation = + PalletInstance(::index() as u8).into(); pub CheckingAccount: AccountId = PolkadotXcm::check_account(); } @@ -482,7 +484,7 @@ pub type FungiblesTransactor = FungiblesAdapter< ConvertedConcreteAssetId< AssetId, Balance, - AsPrefixedGeneralIndex, + AsPrefixedGeneralIndex, JustTry, >, // Convert an XCM MultiLocation into a local account id: @@ -506,7 +508,7 @@ pub type XcmOriginToTransactDispatchOrigin = ( // 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, - // Native converter for Relay-chain (Parent) location; will converts to a `Relay` origin when + // Native converter for Relay-chain (Parent) location; will convert to a `Relay` origin when // recognised. RelayChainAsNative, // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when @@ -523,8 +525,8 @@ pub type XcmOriginToTransactDispatchOrigin = ( ); parameter_types! { - // One XCM operation is 1_000_000 weight - almost certainly a conservative estimate. - pub UnitWeightCost: Weight = 1_000_000; + // One XCM operation is 1_000_000_000 weight - almost certainly a conservative estimate. + pub UnitWeightCost: Weight = 1_000_000_000; pub const MaxInstructions: u32 = 100; pub const MaxAssetsIntoHolding: u32 = 64; } @@ -535,12 +537,22 @@ match_type! { MultiLocation { parents: 1, interior: X1(Plurality { id: BodyId::Executive, .. }) } }; } +match_type! { + pub type ParentOrSiblings: impl Contains = { + MultiLocation { parents: 1, interior: Here } | + MultiLocation { parents: 1, interior: X1(_) } + }; +} pub type Barrier = ( TakeWeightCredit, AllowTopLevelPaidExecutionFrom, + // Parent and its exec plurality get free execution AllowUnpaidExecutionFrom, - // ^^^ Parent and its exec plurality get free execution + // Expected responses are OK. + AllowKnownQueryResponses, + // Subscriptions for version tracking are OK. + AllowSubscriptionsFrom, ); pub struct XcmConfig; @@ -574,7 +586,7 @@ pub type LocalOriginToLocation = (); /// queues. pub type XcmRouter = ( // Two routers - use UMP to communicate with the relay chain: - cumulus_primitives_utility::ParentAsUmp, + cumulus_primitives_utility::ParentAsUmp, // ..and XCMP to communicate with the sibling chains. XcmpQueue, ); @@ -586,8 +598,8 @@ impl pallet_xcm::Config for Runtime { type ExecuteXcmOrigin = EnsureXcmOrigin; type XcmExecuteFilter = Nothing; type XcmExecutor = XcmExecutor; - type XcmTeleportFilter = Everything; - type XcmReserveTransferFilter = Everything; + type XcmTeleportFilter = Nothing; + type XcmReserveTransferFilter = Nothing; type Weigher = FixedWeightBounds; type LocationInverter = LocationInverter; type Origin = Origin; @@ -605,7 +617,8 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime { type Event = Event; type XcmExecutor = XcmExecutor; type ChannelInfo = ParachainSystem; - type VersionWrapper = (); + type VersionWrapper = PolkadotXcm; + type ExecuteOverweightOrigin = EnsureRoot; } impl cumulus_pallet_dmp_queue::Config for Runtime { @@ -649,11 +662,8 @@ parameter_types! { } /// We allow root and the Relay Chain council to execute privileged collator selection operations. -pub type CollatorSelectionUpdateOrigin = EnsureOneOf< - AccountId, - EnsureRoot, - EnsureXcm>, ->; +pub type CollatorSelectionUpdateOrigin = + EnsureOneOf, EnsureXcm>>; impl pallet_collator_selection::Config for Runtime { type Event = Event; @@ -719,7 +729,7 @@ construct_runtime!( ParachainSystem: cumulus_pallet_parachain_system::{ Pallet, Call, Config, Storage, Inherent, Event, ValidateUnsigned, } = 1, - RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Pallet, Storage} = 2, + // RandomnessCollectiveFlip = 2 removed Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent} = 3, ParachainInfo: parachain_info::{Pallet, Storage, Config} = 4, @@ -728,7 +738,7 @@ construct_runtime!( TransactionPayment: pallet_transaction_payment::{Pallet, Storage} = 11, AssetTxPayment: pallet_asset_tx_payment::{Pallet} = 12, - // Collator support. the order of these 4 are important and shall not change. + // Collator support. the order of these 5 are important and shall not change. Authorship: pallet_authorship::{Pallet, Call, Storage} = 20, CollatorSelection: pallet_collator_selection::{Pallet, Call, Storage, Event, Config} = 21, Session: pallet_session::{Pallet, Call, Storage, Event, Config} = 22, @@ -737,7 +747,7 @@ construct_runtime!( // XCM helpers. XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event} = 30, - PolkadotXcm: pallet_xcm::{Pallet, Call, Event, Origin} = 31, + PolkadotXcm: pallet_xcm::{Pallet, Call, Storage, Event, Origin} = 31, CumulusXcm: cumulus_pallet_xcm::{Pallet, Event, Origin} = 32, DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event} = 33, @@ -746,7 +756,7 @@ construct_runtime!( Multisig: pallet_multisig::{Pallet, Call, Storage, Event} = 41, Proxy: pallet_proxy::{Pallet, Call, Storage, Event} = 42, - // The main stage. To include pallet-assets-freezer and pallet-uniques. + // The main stage. Assets: pallet_assets::{Pallet, Call, Storage, Event} = 50, Uniques: pallet_uniques::{Pallet, Call, Storage, Event} = 51, } @@ -762,6 +772,7 @@ pub type SignedBlock = generic::SignedBlock; pub type BlockId = generic::BlockId; /// The SignedExtension to the basic transaction logic. pub type SignedExtra = ( + frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, frame_system::CheckGenesis, @@ -780,7 +791,7 @@ pub type Executive = frame_executive::Executive< Block, frame_system::ChainContext, Runtime, - AllPallets, + AllPalletsWithSystem, >; impl_runtime_apis! { @@ -890,6 +901,19 @@ impl_runtime_apis! { } } + #[cfg(feature = "try-runtime")] + impl frame_try_runtime::TryRuntime for Runtime { + fn on_runtime_upgrade() -> (Weight, Weight) { + log::info!("try-runtime::on_runtime_upgrade statemint."); + let weight = Executive::try_runtime_upgrade().unwrap(); + (weight, RuntimeBlockWeights::get().max_block) + } + + fn execute_block_no_check(block: Block) -> Weight { + Executive::execute_block_no_check(block) + } + } + #[cfg(feature = "runtime-benchmarks")] impl frame_benchmarking::Benchmark for Runtime { fn benchmark_metadata(extra: bool) -> ( @@ -952,6 +976,7 @@ impl_runtime_apis! { add_benchmark!(params, batches, pallet_multisig, Multisig); add_benchmark!(params, batches, pallet_proxy, Proxy); add_benchmark!(params, batches, pallet_session, SessionBench::); + add_benchmark!(params, batches, pallet_uniques, Uniques); add_benchmark!(params, batches, pallet_utility, Utility); add_benchmark!(params, batches, pallet_timestamp, Timestamp); add_benchmark!(params, batches, pallet_collator_selection, CollatorSelection); diff --git a/polkadot-parachains/statemint/src/weights/pallet_assets.rs b/polkadot-parachains/statemint/src/weights/pallet_assets.rs index d8fec88ccf..207ae82dc2 100644 --- a/polkadot-parachains/statemint/src/weights/pallet_assets.rs +++ b/polkadot-parachains/statemint/src/weights/pallet_assets.rs @@ -1,11 +1,27 @@ -//! Autogenerated weights for pallet_assets +// Copyright 2021 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_assets` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-05-31, STEPS: `[50, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2021-10-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemint-dev"), DB CACHE: 128 // Executed Command: -// ./target/release/statemint +// ./target/release/polkadot-collator // benchmark // --chain=statemint-dev // --execution=wasm @@ -15,145 +31,197 @@ // --steps=50 // --repeat=20 // --raw -// --output=./runtime/statemint/src/weights/ +// --header=./file_header.txt +// --output=./polkadot-parachains/statemint/src/weights + +#![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; use sp_std::marker::PhantomData; -/// Weight functions for pallet_assets. +/// Weight functions for `pallet_assets`. pub struct WeightInfo(PhantomData); impl pallet_assets::WeightInfo for WeightInfo { + // Storage: Assets Asset (r:1 w:1) fn create() -> Weight { - (44_125_000 as Weight) + (40_470_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Assets Asset (r:1 w:1) fn force_create() -> Weight { - (22_842_000 as Weight) + (21_173_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - fn destroy(c: u32, s: u32, a: u32) -> Weight { + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Account (r:5002 w:5001) + // Storage: System Account (r:5000 w:5000) + // Storage: Assets Metadata (r:1 w:0) + // Storage: Assets Approvals (r:501 w:500) + fn destroy(c: u32, s: u32, a: u32, ) -> Weight { (0 as Weight) - // Standard Error: 37_000 - .saturating_add((21_822_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 37_000 - .saturating_add((29_044_000 as Weight).saturating_mul(s as Weight)) - // Standard Error: 370_000 - .saturating_add((3_000_000 as Weight).saturating_mul(a as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) + // Standard Error: 40_000 + .saturating_add((19_936_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 40_000 + .saturating_add((25_700_000 as Weight).saturating_mul(s as Weight)) + // Standard Error: 400_000 + .saturating_add((29_566_000 as Weight).saturating_mul(a as Weight)) + .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(c as Weight))) .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) + .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(a as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) .saturating_add(T::DbWeight::get().writes((2 as Weight).saturating_mul(c as Weight))) .saturating_add(T::DbWeight::get().writes((2 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(a as Weight))) } + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Account (r:1 w:1) fn mint() -> Weight { - (49_933_000 as Weight) + (46_147_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Account (r:1 w:1) fn burn() -> Weight { - (56_434_000 as Weight) + (52_364_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Account (r:2 w:2) + // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - (85_393_000 as Weight) + (79_240_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Account (r:2 w:2) + // Storage: System Account (r:1 w:1) fn transfer_keep_alive() -> Weight { - (72_039_000 as Weight) + (66_317_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Account (r:2 w:2) + // Storage: System Account (r:1 w:1) fn force_transfer() -> Weight { - (85_214_000 as Weight) + (79_095_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } + // Storage: Assets Asset (r:1 w:0) + // Storage: Assets Account (r:1 w:1) fn freeze() -> Weight { - (31_915_000 as Weight) + (31_426_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Assets Asset (r:1 w:0) + // Storage: Assets Account (r:1 w:1) fn thaw() -> Weight { - (31_296_000 as Weight) + (31_327_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Assets Asset (r:1 w:1) fn freeze_asset() -> Weight { - (22_272_000 as Weight) + (24_033_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Assets Asset (r:1 w:1) fn thaw_asset() -> Weight { - (22_336_000 as Weight) + (23_925_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Metadata (r:1 w:0) fn transfer_ownership() -> Weight { - (25_526_000 as Weight) + (26_504_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Assets Asset (r:1 w:1) fn set_team() -> Weight { - (22_632_000 as Weight) + (23_963_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - fn set_metadata(_n: u32, s: u32) -> Weight { - (50_330_000 as Weight) + // Storage: Assets Asset (r:1 w:0) + // Storage: Assets Metadata (r:1 w:1) + fn set_metadata(_n: u32, s: u32, ) -> Weight { + (48_256_000 as Weight) // Standard Error: 0 - .saturating_add((9_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((4_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Assets Asset (r:1 w:0) + // Storage: Assets Metadata (r:1 w:1) fn clear_metadata() -> Weight { - (48_266_000 as Weight) + (46_557_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - fn force_set_metadata(_n: u32, s: u32) -> Weight { - (26_249_000 as Weight) + // Storage: Assets Asset (r:1 w:0) + // Storage: Assets Metadata (r:1 w:1) + fn force_set_metadata(_n: u32, s: u32, ) -> Weight { + (25_864_000 as Weight) // Standard Error: 0 - .saturating_add((6_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((5_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Assets Asset (r:1 w:0) + // Storage: Assets Metadata (r:1 w:1) fn force_clear_metadata() -> Weight { - (49_616_000 as Weight) + (46_158_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Assets Asset (r:1 w:1) fn force_asset_status() -> Weight { - (22_596_000 as Weight) + (22_197_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Approvals (r:1 w:1) fn approve_transfer() -> Weight { - (48_708_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + (54_663_000 as Weight) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: Assets Approvals (r:1 w:1) + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Account (r:2 w:2) + // Storage: System Account (r:1 w:1) fn transfer_approved() -> Weight { - (108_476_000 as Weight) + (103_930_000 as Weight) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Approvals (r:1 w:1) fn cancel_approval() -> Weight { - (49_157_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) - } - fn force_cancel_approval() -> Weight { - (56_862_000 as Weight) + (55_023_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Approvals (r:1 w:1) + fn force_cancel_approval() -> Weight { + (56_860_000 as Weight) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } } diff --git a/polkadot-parachains/statemint/src/weights/pallet_balances.rs b/polkadot-parachains/statemint/src/weights/pallet_balances.rs index 9511a01760..43aacebfa5 100644 --- a/polkadot-parachains/statemint/src/weights/pallet_balances.rs +++ b/polkadot-parachains/statemint/src/weights/pallet_balances.rs @@ -1,11 +1,27 @@ -//! Autogenerated weights for pallet_balances +// Copyright 2021 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_balances` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-05-31, STEPS: `[50, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2021-10-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemint-dev"), DB CACHE: 128 // Executed Command: -// ./target/release/statemint +// ./target/release/polkadot-collator // benchmark // --chain=statemint-dev // --execution=wasm @@ -15,50 +31,59 @@ // --steps=50 // --repeat=20 // --raw -// --output=./runtime/statemint/src/weights/ +// --header=./file_header.txt +// --output=./polkadot-parachains/statemint/src/weights + +#![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; use sp_std::marker::PhantomData; -/// Weight functions for pallet_balances. +/// Weight functions for `pallet_balances`. pub struct WeightInfo(PhantomData); impl pallet_balances::WeightInfo for WeightInfo { + // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - (79_601_000 as Weight) + (70_349_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: System Account (r:1 w:1) fn transfer_keep_alive() -> Weight { - (58_429_000 as Weight) + (52_291_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: System Account (r:1 w:1) fn set_balance_creating() -> Weight { - (29_124_000 as Weight) + (28_785_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: System Account (r:1 w:1) fn set_balance_killing() -> Weight { - (36_476_000 as Weight) + (35_051_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: System Account (r:2 w:2) fn force_transfer() -> Weight { - (78_772_000 as Weight) + (70_808_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) fn transfer_all() -> Weight { - (84_170_000 as Weight) + (65_900_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) fn force_unreserve() -> Weight { - (27_766_000 as Weight) + (26_431_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } diff --git a/polkadot-parachains/statemint/src/weights/pallet_collator_selection.rs b/polkadot-parachains/statemint/src/weights/pallet_collator_selection.rs index 328b8c1220..53b9fd764d 100644 --- a/polkadot-parachains/statemint/src/weights/pallet_collator_selection.rs +++ b/polkadot-parachains/statemint/src/weights/pallet_collator_selection.rs @@ -1,11 +1,27 @@ -//! Autogenerated weights for pallet_collator_selection +// Copyright 2021 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_collator_selection` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-05-31, STEPS: `[50, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2021-10-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemint-dev"), DB CACHE: 128 // Executed Command: -// ./target/release/statemint +// ./target/release/polkadot-collator // benchmark // --chain=statemint-dev // --execution=wasm @@ -15,57 +31,80 @@ // --steps=50 // --repeat=20 // --raw -// --output=./runtime/statemint/src/weights/ +// --header=./file_header.txt +// --output=./polkadot-parachains/statemint/src/weights + +#![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; use sp_std::marker::PhantomData; -/// Weight functions for pallet_collator_selection. +/// Weight functions for `pallet_collator_selection`. pub struct WeightInfo(PhantomData); impl pallet_collator_selection::WeightInfo for WeightInfo { - fn set_invulnerables(b: u32) -> Weight { - (18_563_000 as Weight) + // Storage: CollatorSelection Invulnerables (r:0 w:1) + fn set_invulnerables(b: u32, ) -> Weight { + (17_330_000 as Weight) // Standard Error: 0 - .saturating_add((68_000 as Weight).saturating_mul(b as Weight)) + .saturating_add((50_000 as Weight).saturating_mul(b as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: CollatorSelection DesiredCandidates (r:0 w:1) fn set_desired_candidates() -> Weight { - (16_363_000 as Weight).saturating_add(T::DbWeight::get().writes(1 as Weight)) + (15_234_000 as Weight) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: CollatorSelection CandidacyBond (r:0 w:1) fn set_candidacy_bond() -> Weight { - (16_840_000 as Weight).saturating_add(T::DbWeight::get().writes(1 as Weight)) + (15_950_000 as Weight) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - fn register_as_candidate(c: u32) -> Weight { - (71_196_000 as Weight) - // Standard Error: 0 - .saturating_add((198_000 as Weight).saturating_mul(c as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) + // Storage: CollatorSelection Candidates (r:1 w:1) + // Storage: CollatorSelection DesiredCandidates (r:1 w:0) + // Storage: CollatorSelection Invulnerables (r:1 w:0) + // Storage: Session NextKeys (r:1 w:0) + // Storage: CollatorSelection CandidacyBond (r:1 w:0) + // Storage: CollatorSelection LastAuthoredBlock (r:0 w:1) + fn register_as_candidate(c: u32, ) -> Weight { + (74_091_000 as Weight) + // Standard Error: 1_000 + .saturating_add((147_000 as Weight).saturating_mul(c as Weight)) + .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } - fn leave_intent(c: u32) -> Weight { - (55_336_000 as Weight) - // Standard Error: 0 - .saturating_add((151_000 as Weight).saturating_mul(c as Weight)) + // Storage: CollatorSelection Candidates (r:1 w:1) + // Storage: CollatorSelection LastAuthoredBlock (r:0 w:1) + fn leave_intent(c: u32, ) -> Weight { + (69_683_000 as Weight) + // Standard Error: 1_000 + .saturating_add((205_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:2 w:2) + // Storage: System BlockWeight (r:1 w:1) + // Storage: CollatorSelection LastAuthoredBlock (r:0 w:1) fn note_author() -> Weight { - (71_461_000 as Weight) + (63_032_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } - fn new_session(r: u32, c: u32) -> Weight { + // Storage: CollatorSelection Candidates (r:1 w:1) + // Storage: CollatorSelection LastAuthoredBlock (r:1000 w:1) + // Storage: System Account (r:1 w:1) + // Storage: CollatorSelection Invulnerables (r:1 w:0) + // Storage: System BlockWeight (r:1 w:1) + fn new_session(r: u32, c: u32, ) -> Weight { (0 as Weight) - // Standard Error: 1_010_000 - .saturating_add((109_961_000 as Weight).saturating_mul(r as Weight)) - // Standard Error: 1_010_000 - .saturating_add((151_952_000 as Weight).saturating_mul(c as Weight)) - .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) + // Standard Error: 4_328_000 + .saturating_add((24_193_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 4_328_000 + .saturating_add((113_459_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(c as Weight))) - .saturating_add(T::DbWeight::get().writes((2 as Weight).saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes((2 as Weight).saturating_mul(c as Weight))) + .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(r as Weight))) + .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(c as Weight))) } } diff --git a/polkadot-parachains/statemint/src/weights/pallet_multisig.rs b/polkadot-parachains/statemint/src/weights/pallet_multisig.rs index b79a8e0cad..5d08be4082 100644 --- a/polkadot-parachains/statemint/src/weights/pallet_multisig.rs +++ b/polkadot-parachains/statemint/src/weights/pallet_multisig.rs @@ -1,11 +1,27 @@ -//! Autogenerated weights for pallet_multisig +// Copyright 2021 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_multisig` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-05-31, STEPS: `[50, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2021-10-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemint-dev"), DB CACHE: 128 // Executed Command: -// ./target/release/statemint +// ./target/release/polkadot-collator // benchmark // --chain=statemint-dev // --execution=wasm @@ -15,92 +31,115 @@ // --steps=50 // --repeat=20 // --raw -// --output=./runtime/statemint/src/weights/ +// --header=./file_header.txt +// --output=./polkadot-parachains/statemint/src/weights + +#![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; use sp_std::marker::PhantomData; -/// Weight functions for pallet_multisig. +/// Weight functions for `pallet_multisig`. pub struct WeightInfo(PhantomData); impl pallet_multisig::WeightInfo for WeightInfo { - fn as_multi_threshold_1(z: u32) -> Weight { - (14_936_000 as Weight) + fn as_multi_threshold_1(z: u32, ) -> Weight { + (20_481_000 as Weight) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(z as Weight)) } - fn as_multi_create(s: u32, z: u32) -> Weight { - (56_090_000 as Weight) - // Standard Error: 1_000 - .saturating_add((63_000 as Weight).saturating_mul(s as Weight)) + // Storage: Multisig Multisigs (r:1 w:1) + // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) + fn as_multi_create(s: u32, z: u32, ) -> Weight { + (52_126_000 as Weight) // Standard Error: 0 - .saturating_add((1_000 as Weight).saturating_mul(z as Weight)) + .saturating_add((165_000 as Weight).saturating_mul(s as Weight)) + // Standard Error: 0 + .saturating_add((2_000 as Weight).saturating_mul(z as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - fn as_multi_create_store(s: u32, z: u32) -> Weight { - (62_519_000 as Weight) + // Storage: Multisig Multisigs (r:1 w:1) + // Storage: Multisig Calls (r:1 w:1) + // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) + fn as_multi_create_store(s: u32, z: u32, ) -> Weight { + (57_999_000 as Weight) // Standard Error: 1_000 - .saturating_add((66_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((162_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 - .saturating_add((3_000 as Weight).saturating_mul(z as Weight)) + .saturating_add((2_000 as Weight).saturating_mul(z as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } - fn as_multi_approve(s: u32, z: u32) -> Weight { - (30_781_000 as Weight) + // Storage: Multisig Multisigs (r:1 w:1) + fn as_multi_approve(s: u32, z: u32, ) -> Weight { + (33_274_000 as Weight) // Standard Error: 0 - .saturating_add((111_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((157_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(z as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - fn as_multi_approve_store(s: u32, z: u32) -> Weight { - (60_393_000 as Weight) + // Storage: Multisig Multisigs (r:1 w:1) + // Storage: Multisig Calls (r:1 w:1) + fn as_multi_approve_store(s: u32, z: u32, ) -> Weight { + (55_348_000 as Weight) // Standard Error: 0 - .saturating_add((118_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((168_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 .saturating_add((3_000 as Weight).saturating_mul(z as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } - fn as_multi_complete(s: u32, z: u32) -> Weight { - (81_704_000 as Weight) + // Storage: Multisig Multisigs (r:1 w:1) + // Storage: Multisig Calls (r:1 w:1) + // Storage: System Account (r:1 w:1) + fn as_multi_complete(s: u32, z: u32, ) -> Weight { + (70_801_000 as Weight) // Standard Error: 1_000 - .saturating_add((248_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((251_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 - .saturating_add((5_000 as Weight).saturating_mul(z as Weight)) + .saturating_add((4_000 as Weight).saturating_mul(z as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } - fn approve_as_multi_create(s: u32) -> Weight { - (55_585_000 as Weight) - // Standard Error: 1_000 - .saturating_add((115_000 as Weight).saturating_mul(s as Weight)) + // Storage: Multisig Multisigs (r:1 w:1) + // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) + fn approve_as_multi_create(s: u32, ) -> Weight { + (51_302_000 as Weight) + // Standard Error: 0 + .saturating_add((162_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - fn approve_as_multi_approve(s: u32) -> Weight { - (33_483_000 as Weight) - // Standard Error: 1_000 - .saturating_add((82_000 as Weight).saturating_mul(s as Weight)) + // Storage: Multisig Multisigs (r:1 w:1) + // Storage: Multisig Calls (r:1 w:0) + fn approve_as_multi_approve(s: u32, ) -> Weight { + (30_732_000 as Weight) + // Standard Error: 0 + .saturating_add((161_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - fn approve_as_multi_complete(s: u32) -> Weight { - (154_732_000 as Weight) - // Standard Error: 1_000 - .saturating_add((253_000 as Weight).saturating_mul(s as Weight)) + // Storage: Multisig Multisigs (r:1 w:1) + // Storage: Multisig Calls (r:1 w:1) + // Storage: System Account (r:1 w:1) + fn approve_as_multi_complete(s: u32, ) -> Weight { + (105_647_000 as Weight) + // Standard Error: 0 + .saturating_add((267_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } - fn cancel_as_multi(s: u32) -> Weight { - (104_447_000 as Weight) - // Standard Error: 1_000 - .saturating_add((114_000 as Weight).saturating_mul(s as Weight)) + // Storage: Multisig Multisigs (r:1 w:1) + // Storage: Multisig Calls (r:1 w:1) + fn cancel_as_multi(s: u32, ) -> Weight { + (82_671_000 as Weight) + // Standard Error: 0 + .saturating_add((154_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } diff --git a/polkadot-parachains/statemint/src/weights/pallet_proxy.rs b/polkadot-parachains/statemint/src/weights/pallet_proxy.rs index 493ebdfbcb..18e4202bec 100644 --- a/polkadot-parachains/statemint/src/weights/pallet_proxy.rs +++ b/polkadot-parachains/statemint/src/weights/pallet_proxy.rs @@ -1,11 +1,27 @@ -//! Autogenerated weights for pallet_proxy +// Copyright 2021 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 3.0.0 -//! DATE: 2021-05-31, STEPS: `[50, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2021-10-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemint-dev"), DB CACHE: 128 // Executed Command: -// ./target/release/statemint +// ./target/release/polkadot-collator // benchmark // --chain=statemint-dev // --execution=wasm @@ -15,91 +31,111 @@ // --steps=50 // --repeat=20 // --raw -// --output=./runtime/statemint/src/weights/ +// --header=./file_header.txt +// --output=./polkadot-parachains/statemint/src/weights + +#![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; use sp_std::marker::PhantomData; -/// Weight functions for pallet_proxy. +/// Weight functions for `pallet_proxy`. pub struct WeightInfo(PhantomData); impl pallet_proxy::WeightInfo for WeightInfo { - fn proxy(p: u32) -> Weight { - (27_585_000 as Weight) - // Standard Error: 1_000 - .saturating_add((203_000 as Weight).saturating_mul(p as Weight)) + // Storage: Proxy Proxies (r:1 w:0) + fn proxy(p: u32, ) -> Weight { + (23_855_000 as Weight) + // Standard Error: 2_000 + .saturating_add((136_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) } - fn proxy_announced(a: u32, p: u32) -> Weight { - (61_093_000 as Weight) + // Storage: Proxy Proxies (r:1 w:0) + // Storage: Proxy Announcements (r:1 w:1) + // Storage: System Account (r:1 w:1) + fn proxy_announced(a: u32, p: u32, ) -> Weight { + (52_719_000 as Weight) // Standard Error: 2_000 - .saturating_add((680_000 as Weight).saturating_mul(a as Weight)) + .saturating_add((498_000 as Weight).saturating_mul(a as Weight)) // Standard Error: 2_000 - .saturating_add((201_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((151_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } - fn remove_announcement(a: u32, p: u32) -> Weight { - (39_494_000 as Weight) + // Storage: Proxy Announcements (r:1 w:1) + // Storage: System Account (r:1 w:1) + fn remove_announcement(a: u32, p: u32, ) -> Weight { + (35_467_000 as Weight) // Standard Error: 2_000 - .saturating_add((686_000 as Weight).saturating_mul(a as Weight)) + .saturating_add((494_000 as Weight).saturating_mul(a as Weight)) // Standard Error: 2_000 - .saturating_add((1_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((27_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } - fn reject_announcement(a: u32, p: u32) -> Weight { - (39_817_000 as Weight) + // Storage: Proxy Announcements (r:1 w:1) + // Storage: System Account (r:1 w:1) + fn reject_announcement(a: u32, p: u32, ) -> Weight { + (35_581_000 as Weight) // Standard Error: 2_000 - .saturating_add((685_000 as Weight).saturating_mul(a as Weight)) + .saturating_add((498_000 as Weight).saturating_mul(a as Weight)) // Standard Error: 2_000 - .saturating_add((1_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((21_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } - fn announce(a: u32, p: u32) -> Weight { - (54_835_000 as Weight) + // Storage: Proxy Proxies (r:1 w:0) + // Storage: Proxy Announcements (r:1 w:1) + // Storage: System Account (r:1 w:1) + fn announce(a: u32, p: u32, ) -> Weight { + (49_663_000 as Weight) // Standard Error: 2_000 - .saturating_add((684_000 as Weight).saturating_mul(a as Weight)) + .saturating_add((486_000 as Weight).saturating_mul(a as Weight)) // Standard Error: 2_000 - .saturating_add((205_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((153_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } - fn add_proxy(p: u32) -> Weight { - (37_625_000 as Weight) - // Standard Error: 2_000 - .saturating_add((300_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) - } - fn remove_proxy(p: u32) -> Weight { - (36_945_000 as Weight) + // Storage: Proxy Proxies (r:1 w:1) + fn add_proxy(p: u32, ) -> Weight { + (42_248_000 as Weight) // Standard Error: 3_000 - .saturating_add((325_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((184_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - fn remove_proxies(p: u32) -> Weight { - (35_128_000 as Weight) - // Standard Error: 1_000 - .saturating_add((209_000 as Weight).saturating_mul(p as Weight)) + // Storage: Proxy Proxies (r:1 w:1) + fn remove_proxy(p: u32, ) -> Weight { + (34_549_000 as Weight) + // Standard Error: 3_000 + .saturating_add((206_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - fn anonymous(p: u32) -> Weight { - (51_624_000 as Weight) - // Standard Error: 1_000 - .saturating_add((41_000 as Weight).saturating_mul(p as Weight)) + // Storage: Proxy Proxies (r:1 w:1) + fn remove_proxies(p: u32, ) -> Weight { + (33_717_000 as Weight) + // Standard Error: 3_000 + .saturating_add((132_000 as Weight).saturating_mul(p as Weight)) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) + // Storage: Proxy Proxies (r:1 w:1) + fn anonymous(p: u32, ) -> Weight { + (47_829_000 as Weight) + // Standard Error: 4_000 + .saturating_add((23_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - fn kill_anonymous(p: u32) -> Weight { - (37_469_000 as Weight) - // Standard Error: 1_000 - .saturating_add((204_000 as Weight).saturating_mul(p as Weight)) + // Storage: Proxy Proxies (r:1 w:1) + fn kill_anonymous(p: u32, ) -> Weight { + (35_775_000 as Weight) + // Standard Error: 2_000 + .saturating_add((126_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } diff --git a/polkadot-parachains/statemint/src/weights/pallet_session.rs b/polkadot-parachains/statemint/src/weights/pallet_session.rs index f8f9ae735a..df1788c177 100644 --- a/polkadot-parachains/statemint/src/weights/pallet_session.rs +++ b/polkadot-parachains/statemint/src/weights/pallet_session.rs @@ -1,7 +1,23 @@ -//! Autogenerated weights for pallet_session +// Copyright 2021 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_session` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-06-08, STEPS: `[50, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2021-10-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemint-dev"), DB CACHE: 128 // Executed Command: @@ -15,24 +31,31 @@ // --steps=50 // --repeat=20 // --raw -// --output=./polkadot-parachains/statemint-runtime/src/weights +// --header=./file_header.txt +// --output=./polkadot-parachains/statemint/src/weights + +#![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; use sp_std::marker::PhantomData; -/// Weight functions for pallet_session. +/// Weight functions for `pallet_session`. pub struct WeightInfo(PhantomData); impl pallet_session::WeightInfo for WeightInfo { + // Storage: Session NextKeys (r:1 w:1) + // Storage: Session KeyOwner (r:1 w:1) fn set_keys() -> Weight { - (25_040_000 as Weight) + (24_826_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: Session NextKeys (r:1 w:1) + // Storage: Session KeyOwner (r:0 w:1) fn purge_keys() -> Weight { - (17_551_000 as Weight) + (17_889_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } diff --git a/polkadot-parachains/statemint/src/weights/pallet_timestamp.rs b/polkadot-parachains/statemint/src/weights/pallet_timestamp.rs index bd8c76a4db..5343923811 100644 --- a/polkadot-parachains/statemint/src/weights/pallet_timestamp.rs +++ b/polkadot-parachains/statemint/src/weights/pallet_timestamp.rs @@ -1,11 +1,27 @@ -//! Autogenerated weights for pallet_timestamp +// Copyright 2021 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_timestamp` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-05-31, STEPS: `[50, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2021-10-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemint-dev"), DB CACHE: 128 // Executed Command: -// ./target/release/statemint +// ./target/release/polkadot-collator // benchmark // --chain=statemint-dev // --execution=wasm @@ -15,23 +31,27 @@ // --steps=50 // --repeat=20 // --raw -// --output=./runtime/statemint/src/weights/ +// --header=./file_header.txt +// --output=./polkadot-parachains/statemint/src/weights + +#![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; use sp_std::marker::PhantomData; -/// Weight functions for pallet_timestamp. +/// Weight functions for `pallet_timestamp`. pub struct WeightInfo(PhantomData); impl pallet_timestamp::WeightInfo for WeightInfo { + // Storage: Timestamp Now (r:1 w:1) fn set() -> Weight { - (7_687_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) + (7_463_000 as Weight) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn on_finalize() -> Weight { - (4_303_000 as Weight) + (4_400_000 as Weight) } } diff --git a/polkadot-parachains/statemint/src/weights/pallet_uniques.rs b/polkadot-parachains/statemint/src/weights/pallet_uniques.rs index 1b42c35be2..e421253bee 100644 --- a/polkadot-parachains/statemint/src/weights/pallet_uniques.rs +++ b/polkadot-parachains/statemint/src/weights/pallet_uniques.rs @@ -14,53 +14,63 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -//! Autogenerated weights for pallet_uniques +//! Autogenerated weights for `pallet_uniques` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-06-02, STEPS: `[50, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemine-dev"), DB CACHE: 128 +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2021-10-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemint-dev"), DB CACHE: 128 // Executed Command: // ./target/release/polkadot-collator // benchmark -// --chain=statemine-dev -// --steps=50 -// --repeat=20 -// --pallet=pallet_uniques -// --extrinsic=* +// --chain=statemint-dev // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 +// --pallet=pallet_uniques +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --raw // --header=./file_header.txt -// --output=./polkadot-parachains/statemine-runtime/src/weights/ +// --output=./polkadot-parachains/statemint/src/weights + +#![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; use sp_std::marker::PhantomData; -/// Weight functions for pallet_uniques. +/// Weight functions for `pallet_uniques`. pub struct WeightInfo(PhantomData); impl pallet_uniques::WeightInfo for WeightInfo { + // Storage: Uniques Class (r:1 w:1) fn create() -> Weight { - (42_199_000 as Weight) + (41_295_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Uniques Class (r:1 w:1) fn force_create() -> Weight { - (21_030_000 as Weight) + (21_168_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - fn destroy(n: u32, m: u32, a: u32) -> Weight { + // Storage: Uniques Class (r:1 w:1) + // Storage: Uniques Asset (r:1 w:0) + // Storage: Uniques Attribute (r:0 w:1000) + // Storage: Uniques ClassMetadataOf (r:0 w:1) + // Storage: Uniques InstanceMetadataOf (r:0 w:1000) + // Storage: Uniques Account (r:0 w:20) + fn destroy(n: u32, m: u32, a: u32, ) -> Weight { (0 as Weight) - // Standard Error: 14_000 - .saturating_add((16_814_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 14_000 - .saturating_add((1_026_000 as Weight).saturating_mul(m as Weight)) - // Standard Error: 14_000 - .saturating_add((952_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 12_000 + .saturating_add((15_340_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 12_000 + .saturating_add((1_028_000 as Weight).saturating_mul(m as Weight)) + // Standard Error: 12_000 + .saturating_add((792_000 as Weight).saturating_mul(a as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -68,102 +78,141 @@ impl pallet_uniques::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(m as Weight))) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(a as Weight))) } + // Storage: Uniques Asset (r:1 w:1) + // Storage: Uniques Class (r:1 w:1) + // Storage: Uniques Account (r:0 w:1) fn mint() -> Weight { - (57_236_000 as Weight) + (54_671_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } + // Storage: Uniques Class (r:1 w:1) + // Storage: Uniques Asset (r:1 w:1) + // Storage: Uniques Account (r:0 w:1) fn burn() -> Weight { - (58_129_000 as Weight) + (57_152_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } + // Storage: Uniques Class (r:1 w:0) + // Storage: Uniques Asset (r:1 w:1) + // Storage: Uniques Account (r:0 w:2) fn transfer() -> Weight { - (42_980_000 as Weight) + (42_605_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } - fn redeposit(i: u32) -> Weight { + // Storage: Uniques Class (r:1 w:1) + // Storage: Uniques Asset (r:100 w:100) + fn redeposit(i: u32, ) -> Weight { (0 as Weight) - // Standard Error: 11_000 - .saturating_add((26_921_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 13_000 + .saturating_add((24_908_000 as Weight).saturating_mul(i as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(i as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) } + // Storage: Uniques Asset (r:1 w:1) + // Storage: Uniques Class (r:1 w:0) fn freeze() -> Weight { - (30_427_000 as Weight) + (29_580_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Uniques Asset (r:1 w:1) + // Storage: Uniques Class (r:1 w:0) fn thaw() -> Weight { - (29_789_000 as Weight) + (29_645_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Uniques Class (r:1 w:1) fn freeze_class() -> Weight { - (21_380_000 as Weight) + (22_009_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Uniques Class (r:1 w:1) fn thaw_class() -> Weight { - (21_430_000 as Weight) + (22_248_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Uniques Class (r:1 w:1) + // Storage: System Account (r:1 w:1) fn transfer_ownership() -> Weight { - (49_331_000 as Weight) + (48_951_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: Uniques Class (r:1 w:1) fn set_team() -> Weight { - (22_305_000 as Weight) + (23_516_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Uniques Class (r:1 w:1) fn force_asset_status() -> Weight { - (21_965_000 as Weight) + (22_564_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Uniques Class (r:1 w:1) + // Storage: Uniques InstanceMetadataOf (r:1 w:0) + // Storage: Uniques Attribute (r:1 w:1) fn set_attribute() -> Weight { - (70_386_000 as Weight) + (69_093_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: Uniques Class (r:1 w:1) + // Storage: Uniques InstanceMetadataOf (r:1 w:0) + // Storage: Uniques Attribute (r:1 w:1) fn clear_attribute() -> Weight { - (63_932_000 as Weight) + (61_525_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: Uniques Class (r:1 w:1) + // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn set_metadata() -> Weight { - (53_647_000 as Weight) + (52_673_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: Uniques Class (r:1 w:1) + // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn clear_metadata() -> Weight { - (52_353_000 as Weight) + (50_329_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: Uniques Class (r:1 w:1) + // Storage: Uniques ClassMetadataOf (r:1 w:1) fn set_class_metadata() -> Weight { - (51_900_000 as Weight) + (51_354_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: Uniques Class (r:1 w:0) + // Storage: Uniques ClassMetadataOf (r:1 w:1) fn clear_class_metadata() -> Weight { - (46_929_000 as Weight) + (46_499_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Uniques Class (r:1 w:0) + // Storage: Uniques Asset (r:1 w:1) fn approve_transfer() -> Weight { - (32_693_000 as Weight) + (31_660_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Uniques Class (r:1 w:0) + // Storage: Uniques Asset (r:1 w:1) fn cancel_approval() -> Weight { - (32_418_000 as Weight) + (32_436_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } diff --git a/polkadot-parachains/statemint/src/weights/pallet_utility.rs b/polkadot-parachains/statemint/src/weights/pallet_utility.rs index 3923c750a6..f604c0cfcd 100644 --- a/polkadot-parachains/statemint/src/weights/pallet_utility.rs +++ b/polkadot-parachains/statemint/src/weights/pallet_utility.rs @@ -1,11 +1,27 @@ -//! Autogenerated weights for pallet_utility +// Copyright 2021 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_utility` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-05-31, STEPS: `[50, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2021-10-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemint-dev"), DB CACHE: 128 // Executed Command: -// ./target/release/statemint +// ./target/release/polkadot-collator // benchmark // --chain=statemint-dev // --execution=wasm @@ -15,28 +31,34 @@ // --steps=50 // --repeat=20 // --raw -// --output=./runtime/statemint/src/weights/ +// --header=./file_header.txt +// --output=./polkadot-parachains/statemint/src/weights + +#![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; use sp_std::marker::PhantomData; -/// Weight functions for pallet_utility. +/// Weight functions for `pallet_utility`. pub struct WeightInfo(PhantomData); impl pallet_utility::WeightInfo for WeightInfo { - fn batch(c: u32) -> Weight { - (15_408_000 as Weight) - // Standard Error: 0 - .saturating_add((4_571_000 as Weight).saturating_mul(c as Weight)) + fn batch(c: u32, ) -> Weight { + (30_046_000 as Weight) + // Standard Error: 3_000 + .saturating_add((6_946_000 as Weight).saturating_mul(c as Weight)) } fn as_derivative() -> Weight { - (7_817_000 as Weight) + (5_187_000 as Weight) } - fn batch_all(c: u32) -> Weight { - (16_520_000 as Weight) - // Standard Error: 0 - .saturating_add((4_571_000 as Weight).saturating_mul(c as Weight)) + fn batch_all(c: u32, ) -> Weight { + (46_068_000 as Weight) + // Standard Error: 4_000 + .saturating_add((7_471_000 as Weight).saturating_mul(c as Weight)) + } + fn dispatch_as() -> Weight { + (14_340_000 as Weight) } } diff --git a/polkadot-parachains/westmint/Cargo.toml b/polkadot-parachains/westmint/Cargo.toml index d4c1b5f8a9..8212f0b895 100644 --- a/polkadot-parachains/westmint/Cargo.toml +++ b/polkadot-parachains/westmint/Cargo.toml @@ -1,17 +1,17 @@ [package] -name = 'westmint-runtime' -version = '1.0.0' +name = "westmint-runtime" +version = "1.0.0" authors = ["Parity Technologies "] -edition = '2018' +edition = "2021" description = "Westend variant of Statemint parachain runtime" [dependencies] codec = { package = "parity-scale-codec", version = "2.3.0", default-features = false, features = ["derive", "max-encoded-len"] } -hex-literal = { version = '0.3.1', optional = true } +hex-literal = { version = "0.3.1", optional = true } log = { version = "0.4.14", default-features = false } parachain-info = { path = "../pallets/parachain-info", default-features = false } scale-info = { version = "1.0.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.101", optional = true, features = ["derive"] } +serde = { version = "1.0.132", optional = true, features = ["derive"] } smallvec = "1.6.1" # Substrate dependencies @@ -34,13 +34,13 @@ frame-support = { git = "https://github.com/paritytech/substrate", default-featu frame-executive = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } frame-system = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } frame-system-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } +pallet-asset-tx-payment = { git = 'https://github.com/paritytech/substrate', default-features = false, branch = "master" } pallet-assets = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } pallet-aura = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } pallet-authorship = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } pallet-balances = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } pallet-multisig = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } pallet-proxy = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } -pallet-randomness-collective-flip = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } pallet-session = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } pallet-sudo = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } pallet-timestamp = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } @@ -62,7 +62,6 @@ cumulus-pallet-xcmp-queue = { path = "../../pallets/xcmp-queue", default-feature cumulus-pallet-xcm = { path = "../../pallets/xcm", default-features = false } cumulus-pallet-session-benchmarking = {path = "../../pallets/session-benchmarking", default-features = false, version = "3.0.0"} cumulus-ping = { path = "../pallets/ping", default-features = false } -pallet-asset-tx-payment = { path = "../../pallets/asset-tx-payment", default-features = false } pallet-collator-selection = { path = "../../pallets/collator-selection", default-features = false } parachains-common = { path = "../parachains-common", default-features = false } @@ -74,6 +73,9 @@ xcm-builder = { git = "https://github.com/paritytech/polkadot", default-features xcm-executor = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" } pallet-xcm = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" } +# Try-runtime stuff +frame-try-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, optional = true , branch = "master" } + [dev-dependencies] hex-literal = "0.3.1" @@ -83,23 +85,27 @@ substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", bran [features] default = [ "std" ] runtime-benchmarks = [ - 'cumulus-pallet-session-benchmarking/runtime-benchmarks', - 'hex-literal', - 'sp-runtime/runtime-benchmarks', - 'xcm-builder/runtime-benchmarks', - 'frame-benchmarking', - 'frame-system-benchmarking', - 'frame-support/runtime-benchmarks', - 'frame-system/runtime-benchmarks', - 'pallet-assets/runtime-benchmarks', - 'pallet-balances/runtime-benchmarks', - 'pallet-multisig/runtime-benchmarks', - 'pallet-proxy/runtime-benchmarks', - 'pallet-uniques/runtime-benchmarks', - 'pallet-utility/runtime-benchmarks', - 'pallet-timestamp/runtime-benchmarks', - 'pallet-xcm/runtime-benchmarks', - 'pallet-collator-selection/runtime-benchmarks', + "cumulus-pallet-session-benchmarking/runtime-benchmarks", + "hex-literal", + "sp-runtime/runtime-benchmarks", + "xcm-builder/runtime-benchmarks", + "frame-benchmarking/runtime-benchmarks", + "frame-system-benchmarking", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-assets/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", + "pallet-multisig/runtime-benchmarks", + "pallet-proxy/runtime-benchmarks", + "pallet-uniques/runtime-benchmarks", + "pallet-utility/runtime-benchmarks", + "pallet-timestamp/runtime-benchmarks", + "pallet-xcm/runtime-benchmarks", + "pallet-collator-selection/runtime-benchmarks", +] +try-runtime = [ + "frame-try-runtime", + "frame-executive/try-runtime", ] std = [ "codec/std", @@ -127,7 +133,6 @@ std = [ "pallet-balances/std", "pallet-multisig/std", "pallet-proxy/std", - "pallet-randomness-collective-flip/std", "pallet-session/std", "pallet-sudo/std", "pallet-timestamp/std", diff --git a/polkadot-parachains/westmint/src/lib.rs b/polkadot-parachains/westmint/src/lib.rs index 7c1853c174..149d3667e4 100644 --- a/polkadot-parachains/westmint/src/lib.rs +++ b/polkadot-parachains/westmint/src/lib.rs @@ -43,7 +43,7 @@ use codec::{Decode, Encode, MaxEncodedLen}; use constants::{currency::*, fee::WeightToFee}; use frame_support::{ construct_runtime, match_type, parameter_types, - traits::{Everything, InstanceFilter}, + traits::{Everything, InstanceFilter, PalletInfoAccess}, weights::{ constants::{BlockExecutionWeight, ExtrinsicBaseWeight}, DispatchClass, IdentityFee, Weight, @@ -70,12 +70,13 @@ use polkadot_parachain::primitives::Sibling; use polkadot_runtime_common::{BlockHashCount, RocksDbWeight, SlowAdjustingFeeUpdate}; use xcm::latest::prelude::*; use xcm_builder::{ - AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, - AsPrefixedGeneralIndex, ConvertedConcreteAssetId, CurrencyAdapter, EnsureXcmOrigin, - FixedWeightBounds, FungiblesAdapter, IsConcrete, LocationInverter, NativeAsset, - ParentAsSuperuser, ParentIsDefault, RelayChainAsNative, SiblingParachainAsNative, - SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, - SovereignSignedViaLocation, TakeWeightCredit, UsingComponents, + AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, + AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, AsPrefixedGeneralIndex, + ConvertedConcreteAssetId, CurrencyAdapter, EnsureXcmOrigin, FixedWeightBounds, + FungiblesAdapter, IsConcrete, LocationInverter, NativeAsset, ParentAsSuperuser, + ParentIsDefault, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, + SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, + UsingComponents, }; use xcm_executor::{traits::JustTry, Config, XcmExecutor}; @@ -90,10 +91,11 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("westmint"), impl_name: create_runtime_str!("westmint"), authoring_version: 1, - spec_version: 5, + spec_version: 600, impl_version: 0, apis: RUNTIME_API_VERSIONS, - transaction_version: 3, + transaction_version: 4, + state_version: 0, }; /// The version information used to identify this runtime when compiled natively. @@ -152,6 +154,7 @@ impl frame_system::Config for Runtime { type SystemWeightInfo = (); type SS58Prefix = SS58Prefix; type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { @@ -212,17 +215,9 @@ impl pallet_transaction_payment::Config for Runtime { type OperationalFeeMultiplier = OperationalFeeMultiplier; } -impl pallet_randomness_collective_flip::Config for Runtime {} - -impl pallet_sudo::Config for Runtime { - type Event = Event; - type Call = Call; -} - -pub type AssetsForceOrigin = EnsureRoot; - parameter_types! { pub const AssetDeposit: Balance = 1 * UNITS; // 1 WND deposit to create asset + pub const AssetAccountDeposit: Balance = 1 * UNITS; // 1 WND for an asset account pub const ApprovalDeposit: Balance = EXISTENTIAL_DEPOSIT; pub const AssetsStringLimit: u32 = 50; /// Key = 32 bytes, Value = 36 bytes (32+1+1+1+1) @@ -231,6 +226,8 @@ parameter_types! { pub const MetadataDepositPerByte: Balance = deposit(0, 1); } +pub type AssetsForceOrigin = EnsureRoot; + impl pallet_assets::Config for Runtime { type Event = Event; type Balance = Balance; @@ -245,6 +242,7 @@ impl pallet_assets::Config for Runtime { type Freezer = (); type Extra = (); type WeightInfo = weights::pallet_assets::WeightInfo; + type AssetAccountDeposit = AssetAccountDeposit; } parameter_types! { @@ -268,6 +266,7 @@ impl pallet_multisig::Config for Runtime { impl pallet_utility::Config for Runtime { type Event = Event; type Call = Call; + type PalletsOrigin = OriginCaller; type WeightInfo = weights::pallet_utility::WeightInfo; } @@ -300,7 +299,7 @@ parameter_types! { pub enum ProxyType { /// Fully permissioned proxy. Can execute any call on behalf of _proxied_. Any, - /// Can execute any call that does not transfer funds, including asset transfers. + /// Can execute any call that does not transfer funds or assets. NonTransfer, /// Proxy with the ability to reject time-delay proxy announcements. CancelProxy, @@ -432,6 +431,8 @@ parameter_types! { pub RelayChainOrigin: Origin = cumulus_pallet_xcm::Origin::Relay.into(); pub Ancestry: MultiLocation = Parachain(ParachainInfo::parachain_id().into()).into(); pub const Local: MultiLocation = Here.into(); + pub AssetsPalletLocation: MultiLocation = + PalletInstance(::index() as u8).into(); pub CheckingAccount: AccountId = PolkadotXcm::check_account(); } @@ -469,7 +470,7 @@ pub type FungiblesTransactor = FungiblesAdapter< ConvertedConcreteAssetId< AssetId, Balance, - AsPrefixedGeneralIndex, + AsPrefixedGeneralIndex, JustTry, >, // Convert an XCM MultiLocation into a local account id: @@ -510,7 +511,8 @@ pub type XcmOriginToTransactDispatchOrigin = ( ); parameter_types! { - pub UnitWeightCost: Weight = 1_000; + // One XCM operation is 1_000_000_000 weight - almost certainly a conservative estimate. + pub UnitWeightCost: Weight = 1_000_000_000; pub const MaxInstructions: u32 = 100; pub const MaxAssetsIntoHolding: u32 = 64; } @@ -525,8 +527,12 @@ match_type! { pub type Barrier = ( TakeWeightCredit, AllowTopLevelPaidExecutionFrom, + // Parent and its plurality get free execution AllowUnpaidExecutionFrom, - // ^^^ Parent & its plurality gets free execution + // Expected responses are OK. + AllowKnownQueryResponses, + // Subscriptions for version tracking are OK. + AllowSubscriptionsFrom, ); pub struct XcmConfig; @@ -560,7 +566,7 @@ pub type LocalOriginToLocation = SignedToAccountId32, + cumulus_primitives_utility::ParentAsUmp, // ..and XCMP to communicate with the sibling chains. XcmpQueue, ); @@ -578,7 +584,6 @@ impl pallet_xcm::Config for Runtime { type LocationInverter = LocationInverter; type Origin = Origin; type Call = Call; - const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; } @@ -592,7 +597,8 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime { type Event = Event; type XcmExecutor = XcmExecutor; type ChannelInfo = ParachainSystem; - type VersionWrapper = (); + type VersionWrapper = PolkadotXcm; + type ExecuteOverweightOrigin = EnsureRoot; } impl cumulus_pallet_dmp_queue::Config for Runtime { @@ -635,10 +641,12 @@ parameter_types! { pub const MaxInvulnerables: u32 = 100; } +pub type CollatorSelectionUpdateOrigin = EnsureRoot; + impl pallet_collator_selection::Config for Runtime { type Event = Event; type Currency = Balances; - type UpdateOrigin = EnsureRoot; + type UpdateOrigin = CollatorSelectionUpdateOrigin; type PotId = PotId; type MaxCandidates = MaxCandidates; type MinCandidates = MinCandidates; @@ -687,6 +695,11 @@ impl pallet_uniques::Config for Runtime { type WeightInfo = weights::pallet_uniques::WeightInfo; } +impl pallet_sudo::Config for Runtime { + type Event = Event; + type Call = Call; +} + // Create the runtime by composing the FRAME pallets that were previously configured. construct_runtime!( pub enum Runtime where @@ -694,44 +707,44 @@ construct_runtime!( NodeBlock = opaque::Block, UncheckedExtrinsic = UncheckedExtrinsic, { - // System support stuff; - System: frame_system::{Pallet, Call, Config, Storage, Event}, + // System support stuff. + System: frame_system::{Pallet, Call, Config, Storage, Event} = 0, ParachainSystem: cumulus_pallet_parachain_system::{ Pallet, Call, Config, Storage, Inherent, Event, ValidateUnsigned, - }, - RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Pallet, Storage}, - Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent}, - ParachainInfo: parachain_info::{Pallet, Storage, Config}, - Sudo: pallet_sudo::{Pallet, Call, Config, Storage, Event}, + } = 1, + // RandomnessCollectiveFlip = 2 removed + Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent} = 3, + ParachainInfo: parachain_info::{Pallet, Storage, Config} = 4, - // Monetary stuff; - Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - TransactionPayment: pallet_transaction_payment::{Pallet, Storage}, + // Monetary stuff. + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event} = 10, + TransactionPayment: pallet_transaction_payment::{Pallet, Storage} = 11, + AssetTxPayment: pallet_asset_tx_payment::{Pallet} = 12, - // Collator support. the order of these 4 are important and shall not change. - Authorship: pallet_authorship::{Pallet, Call, Storage}, - CollatorSelection: pallet_collator_selection::{Pallet, Call, Storage, Event, Config}, - Session: pallet_session::{Pallet, Call, Storage, Event, Config}, - Aura: pallet_aura::{Pallet, Storage, Config}, - AuraExt: cumulus_pallet_aura_ext::{Pallet, Storage, Config}, - - // The main stage. - Utility: pallet_utility::{Pallet, Call, Event}, - Assets: pallet_assets::{Pallet, Call, Storage, Event}, - Multisig: pallet_multisig::{Pallet, Call, Storage, Event}, - Proxy: pallet_proxy::{Pallet, Call, Storage, Event}, + // Collator support. the order of these 5 are important and shall not change. + Authorship: pallet_authorship::{Pallet, Call, Storage} = 20, + CollatorSelection: pallet_collator_selection::{Pallet, Call, Storage, Event, Config} = 21, + Session: pallet_session::{Pallet, Call, Storage, Event, Config} = 22, + Aura: pallet_aura::{Pallet, Storage, Config} = 23, + AuraExt: cumulus_pallet_aura_ext::{Pallet, Storage, Config} = 24, // XCM helpers. - XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event}, - PolkadotXcm: pallet_xcm::{Pallet, Call, Event, Origin}, - CumulusXcm: cumulus_pallet_xcm::{Pallet, Event, Origin}, - DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event}, + XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event} = 30, + PolkadotXcm: pallet_xcm::{Pallet, Call, Storage, Event, Origin} = 31, + CumulusXcm: cumulus_pallet_xcm::{Pallet, Event, Origin} = 32, + DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event} = 33, - // More things for the main stage - Uniques: pallet_uniques::{Pallet, Call, Storage, Event}, + // Handy utilities. + Utility: pallet_utility::{Pallet, Call, Event} = 40, + Multisig: pallet_multisig::{Pallet, Call, Storage, Event} = 41, + Proxy: pallet_proxy::{Pallet, Call, Storage, Event} = 42, - // More Monetary stuff - AssetTxPayment: pallet_asset_tx_payment::{Pallet}, + // The main stage. + Assets: pallet_assets::{Pallet, Call, Storage, Event} = 50, + Uniques: pallet_uniques::{Pallet, Call, Storage, Event} = 51, + + // Sudo pallet to force root + Sudo: pallet_sudo::{Pallet, Call, Config, Storage, Event} = 255, } ); @@ -745,6 +758,7 @@ pub type SignedBlock = generic::SignedBlock; pub type BlockId = generic::BlockId; /// The SignedExtension to the basic transaction logic. pub type SignedExtra = ( + frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, frame_system::CheckGenesis, @@ -763,10 +777,20 @@ pub type Executive = frame_executive::Executive< Block, frame_system::ChainContext, Runtime, - AllPallets, - (), + AllPalletsWithSystem, + RemoveCollectiveFlip, >; +pub struct RemoveCollectiveFlip; +impl frame_support::traits::OnRuntimeUpgrade for RemoveCollectiveFlip { + fn on_runtime_upgrade() -> Weight { + use frame_support::storage::migration; + // Remove the storage value `RandomMaterial` from removed pallet `RandomnessCollectiveFlip` + migration::remove_storage_prefix(b"RandomnessCollectiveFlip", b"RandomMaterial", b""); + ::DbWeight::get().writes(1) + } +} + impl_runtime_apis! { impl sp_consensus_aura::AuraApi for Runtime { fn slot_duration() -> sp_consensus_aura::SlotDuration { @@ -874,6 +898,19 @@ impl_runtime_apis! { } } + #[cfg(feature = "try-runtime")] + impl frame_try_runtime::TryRuntime for Runtime { + fn on_runtime_upgrade() -> (Weight, Weight) { + log::info!("try-runtime::on_runtime_upgrade westmint."); + let weight = Executive::try_runtime_upgrade().unwrap(); + (weight, RuntimeBlockWeights::get().max_block) + } + + fn execute_block_no_check(block: Block) -> Weight { + Executive::execute_block_no_check(block) + } + } + #[cfg(feature = "runtime-benchmarks")] impl frame_benchmarking::Benchmark for Runtime { fn benchmark_metadata(extra: bool) -> ( @@ -936,6 +973,7 @@ impl_runtime_apis! { add_benchmark!(params, batches, pallet_multisig, Multisig); add_benchmark!(params, batches, pallet_proxy, Proxy); add_benchmark!(params, batches, pallet_session, SessionBench::); + add_benchmark!(params, batches, pallet_uniques, Uniques); add_benchmark!(params, batches, pallet_utility, Utility); add_benchmark!(params, batches, pallet_timestamp, Timestamp); add_benchmark!(params, batches, pallet_collator_selection, CollatorSelection); diff --git a/polkadot-parachains/westmint/src/weights/pallet_assets.rs b/polkadot-parachains/westmint/src/weights/pallet_assets.rs index d8fec88ccf..2208ae1371 100644 --- a/polkadot-parachains/westmint/src/weights/pallet_assets.rs +++ b/polkadot-parachains/westmint/src/weights/pallet_assets.rs @@ -1,13 +1,29 @@ -//! Autogenerated weights for pallet_assets +// Copyright 2021 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_assets` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-05-31, STEPS: `[50, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemint-dev"), DB CACHE: 128 +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2021-10-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westmint-dev"), DB CACHE: 128 // Executed Command: -// ./target/release/statemint +// ./target/release/polkadot-collator // benchmark -// --chain=statemint-dev +// --chain=westmint-dev // --execution=wasm // --wasm-execution=compiled // --pallet=pallet_assets @@ -15,145 +31,197 @@ // --steps=50 // --repeat=20 // --raw -// --output=./runtime/statemint/src/weights/ +// --header=./file_header.txt +// --output=./polkadot-parachains/westmint/src/weights + +#![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; use sp_std::marker::PhantomData; -/// Weight functions for pallet_assets. +/// Weight functions for `pallet_assets`. pub struct WeightInfo(PhantomData); impl pallet_assets::WeightInfo for WeightInfo { + // Storage: Assets Asset (r:1 w:1) fn create() -> Weight { - (44_125_000 as Weight) + (42_115_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Assets Asset (r:1 w:1) fn force_create() -> Weight { - (22_842_000 as Weight) + (20_957_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - fn destroy(c: u32, s: u32, a: u32) -> Weight { + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Account (r:5002 w:5001) + // Storage: System Account (r:5000 w:5000) + // Storage: Assets Metadata (r:1 w:0) + // Storage: Assets Approvals (r:501 w:500) + fn destroy(c: u32, s: u32, a: u32, ) -> Weight { (0 as Weight) // Standard Error: 37_000 - .saturating_add((21_822_000 as Weight).saturating_mul(c as Weight)) + .saturating_add((20_091_000 as Weight).saturating_mul(c as Weight)) // Standard Error: 37_000 - .saturating_add((29_044_000 as Weight).saturating_mul(s as Weight)) - // Standard Error: 370_000 - .saturating_add((3_000_000 as Weight).saturating_mul(a as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add((25_878_000 as Weight).saturating_mul(s as Weight)) + // Standard Error: 375_000 + .saturating_add((26_891_000 as Weight).saturating_mul(a as Weight)) + .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(c as Weight))) .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) + .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(a as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) .saturating_add(T::DbWeight::get().writes((2 as Weight).saturating_mul(c as Weight))) .saturating_add(T::DbWeight::get().writes((2 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(a as Weight))) } + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Account (r:1 w:1) fn mint() -> Weight { - (49_933_000 as Weight) + (47_003_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Account (r:1 w:1) fn burn() -> Weight { - (56_434_000 as Weight) + (53_695_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Account (r:2 w:2) + // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - (85_393_000 as Weight) + (80_559_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Account (r:2 w:2) + // Storage: System Account (r:1 w:1) fn transfer_keep_alive() -> Weight { - (72_039_000 as Weight) + (68_552_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Account (r:2 w:2) + // Storage: System Account (r:1 w:1) fn force_transfer() -> Weight { - (85_214_000 as Weight) + (80_838_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } + // Storage: Assets Asset (r:1 w:0) + // Storage: Assets Account (r:1 w:1) fn freeze() -> Weight { - (31_915_000 as Weight) + (32_651_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Assets Asset (r:1 w:0) + // Storage: Assets Account (r:1 w:1) fn thaw() -> Weight { - (31_296_000 as Weight) + (32_610_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Assets Asset (r:1 w:1) fn freeze_asset() -> Weight { - (22_272_000 as Weight) + (24_163_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Assets Asset (r:1 w:1) fn thaw_asset() -> Weight { - (22_336_000 as Weight) + (24_526_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Metadata (r:1 w:0) fn transfer_ownership() -> Weight { - (25_526_000 as Weight) + (27_131_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Assets Asset (r:1 w:1) fn set_team() -> Weight { - (22_632_000 as Weight) + (24_415_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - fn set_metadata(_n: u32, s: u32) -> Weight { - (50_330_000 as Weight) + // Storage: Assets Asset (r:1 w:0) + // Storage: Assets Metadata (r:1 w:1) + fn set_metadata(_n: u32, s: u32, ) -> Weight { + (49_381_000 as Weight) // Standard Error: 0 - .saturating_add((9_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((7_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Assets Asset (r:1 w:0) + // Storage: Assets Metadata (r:1 w:1) fn clear_metadata() -> Weight { - (48_266_000 as Weight) + (47_651_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - fn force_set_metadata(_n: u32, s: u32) -> Weight { - (26_249_000 as Weight) + // Storage: Assets Asset (r:1 w:0) + // Storage: Assets Metadata (r:1 w:1) + fn force_set_metadata(_n: u32, s: u32, ) -> Weight { + (26_013_000 as Weight) // Standard Error: 0 - .saturating_add((6_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((5_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Assets Asset (r:1 w:0) + // Storage: Assets Metadata (r:1 w:1) fn force_clear_metadata() -> Weight { - (49_616_000 as Weight) + (46_592_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Assets Asset (r:1 w:1) fn force_asset_status() -> Weight { - (22_596_000 as Weight) + (22_426_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Approvals (r:1 w:1) fn approve_transfer() -> Weight { - (48_708_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + (55_840_000 as Weight) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: Assets Approvals (r:1 w:1) + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Account (r:2 w:2) + // Storage: System Account (r:1 w:1) fn transfer_approved() -> Weight { - (108_476_000 as Weight) + (105_850_000 as Weight) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Approvals (r:1 w:1) fn cancel_approval() -> Weight { - (49_157_000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) - } - fn force_cancel_approval() -> Weight { - (56_862_000 as Weight) + (56_361_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Approvals (r:1 w:1) + fn force_cancel_approval() -> Weight { + (58_276_000 as Weight) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } } diff --git a/polkadot-parachains/westmint/src/weights/pallet_balances.rs b/polkadot-parachains/westmint/src/weights/pallet_balances.rs index 9511a01760..1c59507d02 100644 --- a/polkadot-parachains/westmint/src/weights/pallet_balances.rs +++ b/polkadot-parachains/westmint/src/weights/pallet_balances.rs @@ -1,13 +1,29 @@ -//! Autogenerated weights for pallet_balances +// Copyright 2021 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_balances` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-05-31, STEPS: `[50, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemint-dev"), DB CACHE: 128 +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2021-10-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westmint-dev"), DB CACHE: 128 // Executed Command: -// ./target/release/statemint +// ./target/release/polkadot-collator // benchmark -// --chain=statemint-dev +// --chain=westmint-dev // --execution=wasm // --wasm-execution=compiled // --pallet=pallet_balances @@ -15,50 +31,59 @@ // --steps=50 // --repeat=20 // --raw -// --output=./runtime/statemint/src/weights/ +// --header=./file_header.txt +// --output=./polkadot-parachains/westmint/src/weights + +#![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; use sp_std::marker::PhantomData; -/// Weight functions for pallet_balances. +/// Weight functions for `pallet_balances`. pub struct WeightInfo(PhantomData); impl pallet_balances::WeightInfo for WeightInfo { + // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - (79_601_000 as Weight) + (70_519_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: System Account (r:1 w:1) fn transfer_keep_alive() -> Weight { - (58_429_000 as Weight) + (53_376_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: System Account (r:1 w:1) fn set_balance_creating() -> Weight { - (29_124_000 as Weight) + (28_794_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: System Account (r:1 w:1) fn set_balance_killing() -> Weight { - (36_476_000 as Weight) + (34_848_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: System Account (r:2 w:2) fn force_transfer() -> Weight { - (78_772_000 as Weight) + (71_145_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:1 w:1) fn transfer_all() -> Weight { - (84_170_000 as Weight) + (66_076_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: System Account (r:1 w:1) fn force_unreserve() -> Weight { - (27_766_000 as Weight) + (26_920_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } diff --git a/polkadot-parachains/westmint/src/weights/pallet_collator_selection.rs b/polkadot-parachains/westmint/src/weights/pallet_collator_selection.rs index 328b8c1220..9ce4c76e82 100644 --- a/polkadot-parachains/westmint/src/weights/pallet_collator_selection.rs +++ b/polkadot-parachains/westmint/src/weights/pallet_collator_selection.rs @@ -1,13 +1,29 @@ -//! Autogenerated weights for pallet_collator_selection +// Copyright 2021 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_collator_selection` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-05-31, STEPS: `[50, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemint-dev"), DB CACHE: 128 +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2021-10-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westmint-dev"), DB CACHE: 128 // Executed Command: -// ./target/release/statemint +// ./target/release/polkadot-collator // benchmark -// --chain=statemint-dev +// --chain=westmint-dev // --execution=wasm // --wasm-execution=compiled // --pallet=pallet_collator_selection @@ -15,57 +31,80 @@ // --steps=50 // --repeat=20 // --raw -// --output=./runtime/statemint/src/weights/ +// --header=./file_header.txt +// --output=./polkadot-parachains/westmint/src/weights + +#![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; use sp_std::marker::PhantomData; -/// Weight functions for pallet_collator_selection. +/// Weight functions for `pallet_collator_selection`. pub struct WeightInfo(PhantomData); impl pallet_collator_selection::WeightInfo for WeightInfo { - fn set_invulnerables(b: u32) -> Weight { - (18_563_000 as Weight) + // Storage: CollatorSelection Invulnerables (r:0 w:1) + fn set_invulnerables(b: u32, ) -> Weight { + (16_616_000 as Weight) // Standard Error: 0 - .saturating_add((68_000 as Weight).saturating_mul(b as Weight)) + .saturating_add((48_000 as Weight).saturating_mul(b as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: CollatorSelection DesiredCandidates (r:0 w:1) fn set_desired_candidates() -> Weight { - (16_363_000 as Weight).saturating_add(T::DbWeight::get().writes(1 as Weight)) + (14_417_000 as Weight) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: CollatorSelection CandidacyBond (r:0 w:1) fn set_candidacy_bond() -> Weight { - (16_840_000 as Weight).saturating_add(T::DbWeight::get().writes(1 as Weight)) + (15_419_000 as Weight) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - fn register_as_candidate(c: u32) -> Weight { - (71_196_000 as Weight) + // Storage: CollatorSelection Candidates (r:1 w:1) + // Storage: CollatorSelection DesiredCandidates (r:1 w:0) + // Storage: CollatorSelection Invulnerables (r:1 w:0) + // Storage: Session NextKeys (r:1 w:0) + // Storage: CollatorSelection CandidacyBond (r:1 w:0) + // Storage: CollatorSelection LastAuthoredBlock (r:0 w:1) + fn register_as_candidate(c: u32, ) -> Weight { + (69_530_000 as Weight) // Standard Error: 0 - .saturating_add((198_000 as Weight).saturating_mul(c as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add((154_000 as Weight).saturating_mul(c as Weight)) + .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } - fn leave_intent(c: u32) -> Weight { - (55_336_000 as Weight) - // Standard Error: 0 - .saturating_add((151_000 as Weight).saturating_mul(c as Weight)) + // Storage: CollatorSelection Candidates (r:1 w:1) + // Storage: CollatorSelection LastAuthoredBlock (r:0 w:1) + fn leave_intent(c: u32, ) -> Weight { + (73_062_000 as Weight) + // Standard Error: 1_000 + .saturating_add((203_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: System Account (r:2 w:2) + // Storage: System BlockWeight (r:1 w:1) + // Storage: CollatorSelection LastAuthoredBlock (r:0 w:1) fn note_author() -> Weight { - (71_461_000 as Weight) + (62_421_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } - fn new_session(r: u32, c: u32) -> Weight { + // Storage: CollatorSelection Candidates (r:1 w:1) + // Storage: CollatorSelection LastAuthoredBlock (r:1000 w:1) + // Storage: System Account (r:1 w:1) + // Storage: CollatorSelection Invulnerables (r:1 w:0) + // Storage: System BlockWeight (r:1 w:1) + fn new_session(r: u32, c: u32, ) -> Weight { (0 as Weight) - // Standard Error: 1_010_000 - .saturating_add((109_961_000 as Weight).saturating_mul(r as Weight)) - // Standard Error: 1_010_000 - .saturating_add((151_952_000 as Weight).saturating_mul(c as Weight)) - .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(r as Weight))) + // Standard Error: 4_331_000 + .saturating_add((24_131_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 4_331_000 + .saturating_add((113_540_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(c as Weight))) - .saturating_add(T::DbWeight::get().writes((2 as Weight).saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes((2 as Weight).saturating_mul(c as Weight))) + .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(r as Weight))) + .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(c as Weight))) } } diff --git a/polkadot-parachains/westmint/src/weights/pallet_multisig.rs b/polkadot-parachains/westmint/src/weights/pallet_multisig.rs index b79a8e0cad..f75e651c93 100644 --- a/polkadot-parachains/westmint/src/weights/pallet_multisig.rs +++ b/polkadot-parachains/westmint/src/weights/pallet_multisig.rs @@ -1,13 +1,29 @@ -//! Autogenerated weights for pallet_multisig +// Copyright 2021 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_multisig` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-05-31, STEPS: `[50, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemint-dev"), DB CACHE: 128 +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2021-10-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westmint-dev"), DB CACHE: 128 // Executed Command: -// ./target/release/statemint +// ./target/release/polkadot-collator // benchmark -// --chain=statemint-dev +// --chain=westmint-dev // --execution=wasm // --wasm-execution=compiled // --pallet=pallet_multisig @@ -15,92 +31,115 @@ // --steps=50 // --repeat=20 // --raw -// --output=./runtime/statemint/src/weights/ +// --header=./file_header.txt +// --output=./polkadot-parachains/westmint/src/weights + +#![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; use sp_std::marker::PhantomData; -/// Weight functions for pallet_multisig. +/// Weight functions for `pallet_multisig`. pub struct WeightInfo(PhantomData); impl pallet_multisig::WeightInfo for WeightInfo { - fn as_multi_threshold_1(z: u32) -> Weight { - (14_936_000 as Weight) + fn as_multi_threshold_1(z: u32, ) -> Weight { + (20_841_000 as Weight) // Standard Error: 0 .saturating_add((1_000 as Weight).saturating_mul(z as Weight)) } - fn as_multi_create(s: u32, z: u32) -> Weight { - (56_090_000 as Weight) + // Storage: Multisig Multisigs (r:1 w:1) + // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) + fn as_multi_create(s: u32, z: u32, ) -> Weight { + (51_049_000 as Weight) // Standard Error: 1_000 - .saturating_add((63_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((158_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 - .saturating_add((1_000 as Weight).saturating_mul(z as Weight)) + .saturating_add((2_000 as Weight).saturating_mul(z as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - fn as_multi_create_store(s: u32, z: u32) -> Weight { - (62_519_000 as Weight) + // Storage: Multisig Multisigs (r:1 w:1) + // Storage: Multisig Calls (r:1 w:1) + // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) + fn as_multi_create_store(s: u32, z: u32, ) -> Weight { + (57_754_000 as Weight) // Standard Error: 1_000 - .saturating_add((66_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((156_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 .saturating_add((3_000 as Weight).saturating_mul(z as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } - fn as_multi_approve(s: u32, z: u32) -> Weight { - (30_781_000 as Weight) + // Storage: Multisig Multisigs (r:1 w:1) + fn as_multi_approve(s: u32, z: u32, ) -> Weight { + (32_270_000 as Weight) // Standard Error: 0 - .saturating_add((111_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((163_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 - .saturating_add((1_000 as Weight).saturating_mul(z as Weight)) + .saturating_add((2_000 as Weight).saturating_mul(z as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - fn as_multi_approve_store(s: u32, z: u32) -> Weight { - (60_393_000 as Weight) - // Standard Error: 0 - .saturating_add((118_000 as Weight).saturating_mul(s as Weight)) + // Storage: Multisig Multisigs (r:1 w:1) + // Storage: Multisig Calls (r:1 w:1) + fn as_multi_approve_store(s: u32, z: u32, ) -> Weight { + (55_101_000 as Weight) + // Standard Error: 1_000 + .saturating_add((172_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 .saturating_add((3_000 as Weight).saturating_mul(z as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } - fn as_multi_complete(s: u32, z: u32) -> Weight { - (81_704_000 as Weight) + // Storage: Multisig Multisigs (r:1 w:1) + // Storage: Multisig Calls (r:1 w:1) + // Storage: System Account (r:1 w:1) + fn as_multi_complete(s: u32, z: u32, ) -> Weight { + (71_355_000 as Weight) // Standard Error: 1_000 - .saturating_add((248_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((257_000 as Weight).saturating_mul(s as Weight)) // Standard Error: 0 - .saturating_add((5_000 as Weight).saturating_mul(z as Weight)) + .saturating_add((4_000 as Weight).saturating_mul(z as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } - fn approve_as_multi_create(s: u32) -> Weight { - (55_585_000 as Weight) - // Standard Error: 1_000 - .saturating_add((115_000 as Weight).saturating_mul(s as Weight)) + // Storage: Multisig Multisigs (r:1 w:1) + // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) + fn approve_as_multi_create(s: u32, ) -> Weight { + (51_638_000 as Weight) + // Standard Error: 0 + .saturating_add((153_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - fn approve_as_multi_approve(s: u32) -> Weight { - (33_483_000 as Weight) - // Standard Error: 1_000 - .saturating_add((82_000 as Weight).saturating_mul(s as Weight)) + // Storage: Multisig Multisigs (r:1 w:1) + // Storage: Multisig Calls (r:1 w:0) + fn approve_as_multi_approve(s: u32, ) -> Weight { + (30_941_000 as Weight) + // Standard Error: 0 + .saturating_add((169_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - fn approve_as_multi_complete(s: u32) -> Weight { - (154_732_000 as Weight) + // Storage: Multisig Multisigs (r:1 w:1) + // Storage: Multisig Calls (r:1 w:1) + // Storage: System Account (r:1 w:1) + fn approve_as_multi_complete(s: u32, ) -> Weight { + (106_270_000 as Weight) // Standard Error: 1_000 - .saturating_add((253_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((267_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } - fn cancel_as_multi(s: u32) -> Weight { - (104_447_000 as Weight) + // Storage: Multisig Multisigs (r:1 w:1) + // Storage: Multisig Calls (r:1 w:1) + fn cancel_as_multi(s: u32, ) -> Weight { + (83_024_000 as Weight) // Standard Error: 1_000 - .saturating_add((114_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((160_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } diff --git a/polkadot-parachains/westmint/src/weights/pallet_proxy.rs b/polkadot-parachains/westmint/src/weights/pallet_proxy.rs index 493ebdfbcb..7226b6215d 100644 --- a/polkadot-parachains/westmint/src/weights/pallet_proxy.rs +++ b/polkadot-parachains/westmint/src/weights/pallet_proxy.rs @@ -1,13 +1,29 @@ -//! Autogenerated weights for pallet_proxy +// Copyright 2021 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 3.0.0 -//! DATE: 2021-05-31, STEPS: `[50, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemint-dev"), DB CACHE: 128 +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2021-10-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westmint-dev"), DB CACHE: 128 // Executed Command: -// ./target/release/statemint +// ./target/release/polkadot-collator // benchmark -// --chain=statemint-dev +// --chain=westmint-dev // --execution=wasm // --wasm-execution=compiled // --pallet=pallet_proxy @@ -15,91 +31,111 @@ // --steps=50 // --repeat=20 // --raw -// --output=./runtime/statemint/src/weights/ +// --header=./file_header.txt +// --output=./polkadot-parachains/westmint/src/weights + +#![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; use sp_std::marker::PhantomData; -/// Weight functions for pallet_proxy. +/// Weight functions for `pallet_proxy`. pub struct WeightInfo(PhantomData); impl pallet_proxy::WeightInfo for WeightInfo { - fn proxy(p: u32) -> Weight { - (27_585_000 as Weight) + // Storage: Proxy Proxies (r:1 w:0) + fn proxy(p: u32, ) -> Weight { + (24_230_000 as Weight) + // Standard Error: 2_000 + .saturating_add((135_000 as Weight).saturating_mul(p as Weight)) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + } + // Storage: Proxy Proxies (r:1 w:0) + // Storage: Proxy Announcements (r:1 w:1) + // Storage: System Account (r:1 w:1) + fn proxy_announced(a: u32, p: u32, ) -> Weight { + (54_025_000 as Weight) + // Standard Error: 2_000 + .saturating_add((486_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 2_000 + .saturating_add((141_000 as Weight).saturating_mul(p as Weight)) + .saturating_add(T::DbWeight::get().reads(3 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } + // Storage: Proxy Announcements (r:1 w:1) + // Storage: System Account (r:1 w:1) + fn remove_announcement(a: u32, p: u32, ) -> Weight { + (36_196_000 as Weight) + // Standard Error: 2_000 + .saturating_add((491_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 2_000 + .saturating_add((17_000 as Weight).saturating_mul(p as Weight)) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } + // Storage: Proxy Announcements (r:1 w:1) + // Storage: System Account (r:1 w:1) + fn reject_announcement(a: u32, p: u32, ) -> Weight { + (36_363_000 as Weight) // Standard Error: 1_000 - .saturating_add((203_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - } - fn proxy_announced(a: u32, p: u32) -> Weight { - (61_093_000 as Weight) + .saturating_add((485_000 as Weight).saturating_mul(a as Weight)) // Standard Error: 2_000 - .saturating_add((680_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 2_000 - .saturating_add((201_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) - } - fn remove_announcement(a: u32, p: u32) -> Weight { - (39_494_000 as Weight) - // Standard Error: 2_000 - .saturating_add((686_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 2_000 - .saturating_add((1_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((13_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } - fn reject_announcement(a: u32, p: u32) -> Weight { - (39_817_000 as Weight) + // Storage: Proxy Proxies (r:1 w:0) + // Storage: Proxy Announcements (r:1 w:1) + // Storage: System Account (r:1 w:1) + fn announce(a: u32, p: u32, ) -> Weight { + (50_945_000 as Weight) // Standard Error: 2_000 - .saturating_add((685_000 as Weight).saturating_mul(a as Weight)) + .saturating_add((480_000 as Weight).saturating_mul(a as Weight)) // Standard Error: 2_000 - .saturating_add((1_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) - } - fn announce(a: u32, p: u32) -> Weight { - (54_835_000 as Weight) - // Standard Error: 2_000 - .saturating_add((684_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 2_000 - .saturating_add((205_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((141_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } - fn add_proxy(p: u32) -> Weight { - (37_625_000 as Weight) - // Standard Error: 2_000 - .saturating_add((300_000 as Weight).saturating_mul(p as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) - } - fn remove_proxy(p: u32) -> Weight { - (36_945_000 as Weight) + // Storage: Proxy Proxies (r:1 w:1) + fn add_proxy(p: u32, ) -> Weight { + (43_040_000 as Weight) // Standard Error: 3_000 - .saturating_add((325_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((184_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - fn remove_proxies(p: u32) -> Weight { - (35_128_000 as Weight) - // Standard Error: 1_000 - .saturating_add((209_000 as Weight).saturating_mul(p as Weight)) + // Storage: Proxy Proxies (r:1 w:1) + fn remove_proxy(p: u32, ) -> Weight { + (35_074_000 as Weight) + // Standard Error: 3_000 + .saturating_add((210_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - fn anonymous(p: u32) -> Weight { - (51_624_000 as Weight) - // Standard Error: 1_000 - .saturating_add((41_000 as Weight).saturating_mul(p as Weight)) + // Storage: Proxy Proxies (r:1 w:1) + fn remove_proxies(p: u32, ) -> Weight { + (34_447_000 as Weight) + // Standard Error: 2_000 + .saturating_add((123_000 as Weight).saturating_mul(p as Weight)) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) + // Storage: Proxy Proxies (r:1 w:1) + fn anonymous(p: u32, ) -> Weight { + (48_525_000 as Weight) + // Standard Error: 3_000 + .saturating_add((25_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - fn kill_anonymous(p: u32) -> Weight { - (37_469_000 as Weight) - // Standard Error: 1_000 - .saturating_add((204_000 as Weight).saturating_mul(p as Weight)) + // Storage: Proxy Proxies (r:1 w:1) + fn kill_anonymous(p: u32, ) -> Weight { + (36_388_000 as Weight) + // Standard Error: 2_000 + .saturating_add((122_000 as Weight).saturating_mul(p as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } diff --git a/polkadot-parachains/westmint/src/weights/pallet_session.rs b/polkadot-parachains/westmint/src/weights/pallet_session.rs index f8f9ae735a..7dc1a71304 100644 --- a/polkadot-parachains/westmint/src/weights/pallet_session.rs +++ b/polkadot-parachains/westmint/src/weights/pallet_session.rs @@ -1,13 +1,29 @@ -//! Autogenerated weights for pallet_session +// Copyright 2021 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_session` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-06-08, STEPS: `[50, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemint-dev"), DB CACHE: 128 +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2021-10-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westmint-dev"), DB CACHE: 128 // Executed Command: // ./target/release/polkadot-collator // benchmark -// --chain=statemint-dev +// --chain=westmint-dev // --execution=wasm // --wasm-execution=compiled // --pallet=pallet_session @@ -15,24 +31,31 @@ // --steps=50 // --repeat=20 // --raw -// --output=./polkadot-parachains/statemint-runtime/src/weights +// --header=./file_header.txt +// --output=./polkadot-parachains/westmint/src/weights + +#![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; use sp_std::marker::PhantomData; -/// Weight functions for pallet_session. +/// Weight functions for `pallet_session`. pub struct WeightInfo(PhantomData); impl pallet_session::WeightInfo for WeightInfo { + // Storage: Session NextKeys (r:1 w:1) + // Storage: Session KeyOwner (r:1 w:1) fn set_keys() -> Weight { - (25_040_000 as Weight) + (25_128_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: Session NextKeys (r:1 w:1) + // Storage: Session KeyOwner (r:0 w:1) fn purge_keys() -> Weight { - (17_551_000 as Weight) + (17_883_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } diff --git a/polkadot-parachains/westmint/src/weights/pallet_timestamp.rs b/polkadot-parachains/westmint/src/weights/pallet_timestamp.rs index bd8c76a4db..f0af098c08 100644 --- a/polkadot-parachains/westmint/src/weights/pallet_timestamp.rs +++ b/polkadot-parachains/westmint/src/weights/pallet_timestamp.rs @@ -1,13 +1,29 @@ -//! Autogenerated weights for pallet_timestamp +// Copyright 2021 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_timestamp` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-05-31, STEPS: `[50, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemint-dev"), DB CACHE: 128 +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2021-10-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westmint-dev"), DB CACHE: 128 // Executed Command: -// ./target/release/statemint +// ./target/release/polkadot-collator // benchmark -// --chain=statemint-dev +// --chain=westmint-dev // --execution=wasm // --wasm-execution=compiled // --pallet=pallet_timestamp @@ -15,23 +31,27 @@ // --steps=50 // --repeat=20 // --raw -// --output=./runtime/statemint/src/weights/ +// --header=./file_header.txt +// --output=./polkadot-parachains/westmint/src/weights + +#![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; use sp_std::marker::PhantomData; -/// Weight functions for pallet_timestamp. +/// Weight functions for `pallet_timestamp`. pub struct WeightInfo(PhantomData); impl pallet_timestamp::WeightInfo for WeightInfo { + // Storage: Timestamp Now (r:1 w:1) fn set() -> Weight { - (7_687_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) + (7_567_000 as Weight) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn on_finalize() -> Weight { - (4_303_000 as Weight) + (4_350_000 as Weight) } } diff --git a/polkadot-parachains/westmint/src/weights/pallet_uniques.rs b/polkadot-parachains/westmint/src/weights/pallet_uniques.rs index 1b42c35be2..f3272166c1 100644 --- a/polkadot-parachains/westmint/src/weights/pallet_uniques.rs +++ b/polkadot-parachains/westmint/src/weights/pallet_uniques.rs @@ -14,53 +14,63 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -//! Autogenerated weights for pallet_uniques +//! Autogenerated weights for `pallet_uniques` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-06-02, STEPS: `[50, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemine-dev"), DB CACHE: 128 +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2021-10-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westmint-dev"), DB CACHE: 128 // Executed Command: // ./target/release/polkadot-collator // benchmark -// --chain=statemine-dev -// --steps=50 -// --repeat=20 -// --pallet=pallet_uniques -// --extrinsic=* +// --chain=westmint-dev // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 +// --pallet=pallet_uniques +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --raw // --header=./file_header.txt -// --output=./polkadot-parachains/statemine-runtime/src/weights/ +// --output=./polkadot-parachains/westmint/src/weights + +#![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; use sp_std::marker::PhantomData; -/// Weight functions for pallet_uniques. +/// Weight functions for `pallet_uniques`. pub struct WeightInfo(PhantomData); impl pallet_uniques::WeightInfo for WeightInfo { + // Storage: Uniques Class (r:1 w:1) fn create() -> Weight { - (42_199_000 as Weight) + (41_131_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Uniques Class (r:1 w:1) fn force_create() -> Weight { - (21_030_000 as Weight) + (21_000_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - fn destroy(n: u32, m: u32, a: u32) -> Weight { + // Storage: Uniques Class (r:1 w:1) + // Storage: Uniques Asset (r:1 w:0) + // Storage: Uniques Attribute (r:0 w:1000) + // Storage: Uniques ClassMetadataOf (r:0 w:1) + // Storage: Uniques InstanceMetadataOf (r:0 w:1000) + // Storage: Uniques Account (r:0 w:20) + fn destroy(n: u32, m: u32, a: u32, ) -> Weight { (0 as Weight) - // Standard Error: 14_000 - .saturating_add((16_814_000 as Weight).saturating_mul(n as Weight)) - // Standard Error: 14_000 - .saturating_add((1_026_000 as Weight).saturating_mul(m as Weight)) - // Standard Error: 14_000 - .saturating_add((952_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 13_000 + .saturating_add((15_431_000 as Weight).saturating_mul(n as Weight)) + // Standard Error: 13_000 + .saturating_add((1_064_000 as Weight).saturating_mul(m as Weight)) + // Standard Error: 13_000 + .saturating_add((802_000 as Weight).saturating_mul(a as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -68,102 +78,141 @@ impl pallet_uniques::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(m as Weight))) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(a as Weight))) } + // Storage: Uniques Asset (r:1 w:1) + // Storage: Uniques Class (r:1 w:1) + // Storage: Uniques Account (r:0 w:1) fn mint() -> Weight { - (57_236_000 as Weight) + (55_067_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } + // Storage: Uniques Class (r:1 w:1) + // Storage: Uniques Asset (r:1 w:1) + // Storage: Uniques Account (r:0 w:1) fn burn() -> Weight { - (58_129_000 as Weight) + (55_722_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } + // Storage: Uniques Class (r:1 w:0) + // Storage: Uniques Asset (r:1 w:1) + // Storage: Uniques Account (r:0 w:2) fn transfer() -> Weight { - (42_980_000 as Weight) + (42_987_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } - fn redeposit(i: u32) -> Weight { + // Storage: Uniques Class (r:1 w:1) + // Storage: Uniques Asset (r:100 w:100) + fn redeposit(i: u32, ) -> Weight { (0 as Weight) - // Standard Error: 11_000 - .saturating_add((26_921_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 14_000 + .saturating_add((24_501_000 as Weight).saturating_mul(i as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(i as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(i as Weight))) } + // Storage: Uniques Asset (r:1 w:1) + // Storage: Uniques Class (r:1 w:0) fn freeze() -> Weight { - (30_427_000 as Weight) + (29_695_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Uniques Asset (r:1 w:1) + // Storage: Uniques Class (r:1 w:0) fn thaw() -> Weight { - (29_789_000 as Weight) + (29_939_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Uniques Class (r:1 w:1) fn freeze_class() -> Weight { - (21_380_000 as Weight) + (22_573_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Uniques Class (r:1 w:1) fn thaw_class() -> Weight { - (21_430_000 as Weight) + (22_485_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Uniques Class (r:1 w:1) + // Storage: System Account (r:1 w:1) fn transfer_ownership() -> Weight { - (49_331_000 as Weight) + (48_454_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: Uniques Class (r:1 w:1) fn set_team() -> Weight { - (22_305_000 as Weight) + (23_828_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Uniques Class (r:1 w:1) fn force_asset_status() -> Weight { - (21_965_000 as Weight) + (22_033_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Uniques Class (r:1 w:1) + // Storage: Uniques InstanceMetadataOf (r:1 w:0) + // Storage: Uniques Attribute (r:1 w:1) fn set_attribute() -> Weight { - (70_386_000 as Weight) + (68_112_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: Uniques Class (r:1 w:1) + // Storage: Uniques InstanceMetadataOf (r:1 w:0) + // Storage: Uniques Attribute (r:1 w:1) fn clear_attribute() -> Weight { - (63_932_000 as Weight) + (61_017_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: Uniques Class (r:1 w:1) + // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn set_metadata() -> Weight { - (53_647_000 as Weight) + (51_170_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: Uniques Class (r:1 w:1) + // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn clear_metadata() -> Weight { - (52_353_000 as Weight) + (50_897_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: Uniques Class (r:1 w:1) + // Storage: Uniques ClassMetadataOf (r:1 w:1) fn set_class_metadata() -> Weight { - (51_900_000 as Weight) + (51_353_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: Uniques Class (r:1 w:0) + // Storage: Uniques ClassMetadataOf (r:1 w:1) fn clear_class_metadata() -> Weight { - (46_929_000 as Weight) + (45_357_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Uniques Class (r:1 w:0) + // Storage: Uniques Asset (r:1 w:1) fn approve_transfer() -> Weight { - (32_693_000 as Weight) + (32_295_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Uniques Class (r:1 w:0) + // Storage: Uniques Asset (r:1 w:1) fn cancel_approval() -> Weight { - (32_418_000 as Weight) + (31_568_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } diff --git a/polkadot-parachains/westmint/src/weights/pallet_utility.rs b/polkadot-parachains/westmint/src/weights/pallet_utility.rs index 3923c750a6..9e1233c500 100644 --- a/polkadot-parachains/westmint/src/weights/pallet_utility.rs +++ b/polkadot-parachains/westmint/src/weights/pallet_utility.rs @@ -1,13 +1,29 @@ -//! Autogenerated weights for pallet_utility +// Copyright 2021 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_utility` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-05-31, STEPS: `[50, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemint-dev"), DB CACHE: 128 +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2021-10-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westmint-dev"), DB CACHE: 128 // Executed Command: -// ./target/release/statemint +// ./target/release/polkadot-collator // benchmark -// --chain=statemint-dev +// --chain=westmint-dev // --execution=wasm // --wasm-execution=compiled // --pallet=pallet_utility @@ -15,28 +31,34 @@ // --steps=50 // --repeat=20 // --raw -// --output=./runtime/statemint/src/weights/ +// --header=./file_header.txt +// --output=./polkadot-parachains/westmint/src/weights + +#![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; use sp_std::marker::PhantomData; -/// Weight functions for pallet_utility. +/// Weight functions for `pallet_utility`. pub struct WeightInfo(PhantomData); impl pallet_utility::WeightInfo for WeightInfo { - fn batch(c: u32) -> Weight { - (15_408_000 as Weight) - // Standard Error: 0 - .saturating_add((4_571_000 as Weight).saturating_mul(c as Weight)) + fn batch(c: u32, ) -> Weight { + (24_709_000 as Weight) + // Standard Error: 3_000 + .saturating_add((6_934_000 as Weight).saturating_mul(c as Weight)) } fn as_derivative() -> Weight { - (7_817_000 as Weight) + (5_317_000 as Weight) } - fn batch_all(c: u32) -> Weight { - (16_520_000 as Weight) - // Standard Error: 0 - .saturating_add((4_571_000 as Weight).saturating_mul(c as Weight)) + fn batch_all(c: u32, ) -> Weight { + (34_015_000 as Weight) + // Standard Error: 3_000 + .saturating_add((7_343_000 as Weight).saturating_mul(c as Weight)) + } + fn dispatch_as() -> Weight { + (14_340_000 as Weight) } } diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 95ac9d8c8e..659ccafdfd 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -2,7 +2,7 @@ name = "cumulus-primitives-core" version = "0.1.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" [dependencies] # Substrate dependencies diff --git a/primitives/core/src/lib.rs b/primitives/core/src/lib.rs index ff35ef5a1c..aed56a8ed6 100644 --- a/primitives/core/src/lib.rs +++ b/primitives/core/src/lib.rs @@ -34,7 +34,7 @@ pub use polkadot_primitives::v1::{ /// A module that re-exports relevant relay chain definitions. pub mod relay_chain { pub use polkadot_core_primitives::*; - pub use polkadot_primitives::{v1, v1::well_known_keys}; + pub use polkadot_primitives::{v1, v1::well_known_keys, v2}; } /// An inbound HRMP message. @@ -122,7 +122,7 @@ pub trait XcmpMessageSource { impl XcmpMessageSource for () { fn take_outbound_messages(_maximum_channels: usize) -> Vec<(ParaId, Vec)> { - vec![] + Vec::new() } } diff --git a/primitives/parachain-inherent/Cargo.toml b/primitives/parachain-inherent/Cargo.toml index b76ec7822d..faca11a915 100644 --- a/primitives/parachain-inherent/Cargo.toml +++ b/primitives/parachain-inherent/Cargo.toml @@ -2,25 +2,24 @@ name = "cumulus-primitives-parachain-inherent" version = "0.1.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" [dependencies] # Substrate dependencies sp-inherents = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } sp-core = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } -sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master", optional = true } -sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", optional = true } +sc-client-api = { git = "https://github.com/paritytech/substrate", optional = true , branch = "master" } +sp-runtime = { git = "https://github.com/paritytech/substrate", optional = true , branch = "master" } sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } -sp-state-machine = { git = "https://github.com/paritytech/substrate", branch = "master", optional = true } +sp-state-machine = { git = "https://github.com/paritytech/substrate", optional = true , branch = "master" } sp-trie = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } -sp-api = { git = "https://github.com/paritytech/substrate", branch = "master", optional = true } - -# Polkadot dependencies -polkadot-client = { git = "https://github.com/paritytech/polkadot", optional = true, branch = "master" } +sp-api = { git = "https://github.com/paritytech/substrate", optional = true , branch = "master" } +sp-storage = { git = "https://github.com/paritytech/substrate", optional = true , branch = "master" } # Cumulus dependencies cumulus-primitives-core = { path = "../core", default-features = false } cumulus-test-relay-sproof-builder = { path = "../../test/relay-sproof-builder", optional = true } +cumulus-relay-chain-interface = { path = "../../client/relay-chain-interface", optional = true } # Other dependencies async-trait = { version = "0.1.42", optional = true } @@ -44,6 +43,8 @@ std = [ "sp-runtime", "sc-client-api", "sp-api", - "polkadot-client", + "sp-storage", + "cumulus-test-relay-sproof-builder", + "cumulus-relay-chain-interface", "cumulus-test-relay-sproof-builder" ] diff --git a/primitives/parachain-inherent/src/client_side.rs b/primitives/parachain-inherent/src/client_side.rs index 3190b992e7..dab368dc6c 100644 --- a/primitives/parachain-inherent/src/client_side.rs +++ b/primitives/parachain-inherent/src/client_side.rs @@ -19,112 +19,35 @@ use crate::ParachainInherentData; use codec::Decode; use cumulus_primitives_core::{ - relay_chain::{ - self, - v1::{HrmpChannelId, ParachainHost}, - Block as PBlock, Hash as PHash, - }, - InboundDownwardMessage, InboundHrmpMessage, ParaId, PersistedValidationData, + relay_chain::{self, v1::HrmpChannelId, Hash as PHash}, + ParaId, PersistedValidationData, }; -use polkadot_client::{Client, ClientHandle, ExecuteWithClient}; -use sc_client_api::Backend; -use sp_api::ProvideRuntimeApi; +use cumulus_relay_chain_interface::RelayChainInterface; use sp_runtime::generic::BlockId; -use sp_state_machine::Backend as _; -use std::collections::BTreeMap; const LOG_TARGET: &str = "parachain-inherent"; -/// Returns the whole contents of the downward message queue for the parachain we are collating -/// for. -/// -/// Returns `None` in case of an error. -fn retrieve_dmq_contents( - polkadot_client: &PClient, - para_id: ParaId, - relay_parent: PHash, -) -> Option> -where - PClient: ProvideRuntimeApi, - PClient::Api: ParachainHost, -{ - polkadot_client - .runtime_api() - .dmq_contents_with_context( - &BlockId::hash(relay_parent), - sp_core::ExecutionContext::Importing, - para_id, - ) - .map_err(|e| { - tracing::error!( - target: LOG_TARGET, - relay_parent = ?relay_parent, - error = ?e, - "An error occured during requesting the downward messages.", - ); - }) - .ok() -} - -/// Returns channels contents for each inbound HRMP channel addressed to the parachain we are -/// collating for. -/// -/// Empty channels are also included. -fn retrieve_all_inbound_hrmp_channel_contents( - polkadot_client: &PClient, - para_id: ParaId, - relay_parent: PHash, -) -> Option>> -where - PClient: ProvideRuntimeApi, - PClient::Api: ParachainHost, -{ - polkadot_client - .runtime_api() - .inbound_hrmp_channels_contents_with_context( - &BlockId::hash(relay_parent), - sp_core::ExecutionContext::Importing, - para_id, - ) - .map_err(|e| { - tracing::error!( - target: LOG_TARGET, - relay_parent = ?relay_parent, - error = ?e, - "An error occured during requesting the inbound HRMP messages.", - ); - }) - .ok() -} - /// Collect the relevant relay chain state in form of a proof for putting it into the validation /// data inherent. fn collect_relay_storage_proof( - polkadot_backend: &impl Backend, + relay_chain_interface: &impl RelayChainInterface, para_id: ParaId, relay_parent: PHash, ) -> Option { use relay_chain::well_known_keys as relay_well_known_keys; - let relay_parent_state_backend = polkadot_backend - .state_at(BlockId::Hash(relay_parent)) + let relay_parent_block_id = BlockId::Hash(relay_parent); + let ingress_channels = relay_chain_interface + .get_storage_by_key( + &relay_parent_block_id, + &relay_well_known_keys::hrmp_ingress_channel_index(para_id), + ) .map_err(|e| { tracing::error!( target: LOG_TARGET, relay_parent = ?relay_parent, error = ?e, - "Cannot obtain the state of the relay chain.", - ) - }) - .ok()?; - - let ingress_channels = relay_parent_state_backend - .storage(&relay_well_known_keys::hrmp_ingress_channel_index(para_id)) - .map_err(|e| { - tracing::error!( - target: LOG_TARGET, - error = ?e, - "Cannot obtain the hrmp ingress channel index." + "Cannot obtain the hrmp ingress channel." ) }) .ok()?; @@ -142,16 +65,20 @@ fn collect_relay_storage_proof( .ok()? .unwrap_or_default(); - let egress_channels = relay_parent_state_backend - .storage(&relay_well_known_keys::hrmp_egress_channel_index(para_id)) + let egress_channels = relay_chain_interface + .get_storage_by_key( + &relay_parent_block_id, + &relay_well_known_keys::hrmp_egress_channel_index(para_id), + ) .map_err(|e| { tracing::error!( target: LOG_TARGET, error = ?e, - "Cannot obtain the hrmp egress channel index.", + "Cannot obtain the hrmp egress channel.", ) }) .ok()?; + let egress_channels = egress_channels .map(|raw| >::decode(&mut &raw[..])) .transpose() @@ -165,7 +92,7 @@ fn collect_relay_storage_proof( .ok()? .unwrap_or_default(); - let mut relevant_keys = vec![]; + let mut relevant_keys = Vec::new(); relevant_keys.push(relay_well_known_keys::CURRENT_SLOT.to_vec()); relevant_keys.push(relay_well_known_keys::ACTIVE_CONFIG.to_vec()); relevant_keys.push(relay_well_known_keys::dmq_mqc_head(para_id)); @@ -181,38 +108,26 @@ fn collect_relay_storage_proof( relay_well_known_keys::hrmp_channels(HrmpChannelId { sender: para_id, recipient }) })); - sp_state_machine::prove_read(relay_parent_state_backend, relevant_keys) - .map_err(|e| { - tracing::error!( - target: LOG_TARGET, - relay_parent = ?relay_parent, - error = ?e, - "Failed to collect required relay chain state storage proof.", - ) - }) - .ok() + relay_chain_interface.prove_read(&relay_parent_block_id, &relevant_keys).ok()? } impl ParachainInherentData { /// Create the [`ParachainInherentData`] at the given `relay_parent`. /// /// Returns `None` if the creation failed. - pub fn create_at( + pub fn create_at( relay_parent: PHash, - polkadot_client: &PClient, - polkadot_backend: &impl Backend, + relay_chain_interface: &impl RelayChainInterface, validation_data: &PersistedValidationData, para_id: ParaId, - ) -> Option - where - PClient: ProvideRuntimeApi, - PClient::Api: ParachainHost, - { + ) -> Option { let relay_chain_state = - collect_relay_storage_proof(polkadot_backend, para_id, relay_parent)?; - let downward_messages = retrieve_dmq_contents(polkadot_client, para_id, relay_parent)?; - let horizontal_messages = - retrieve_all_inbound_hrmp_channel_contents(polkadot_client, para_id, relay_parent)?; + collect_relay_storage_proof(relay_chain_interface, para_id, relay_parent)?; + + let downward_messages = + relay_chain_interface.retrieve_dmq_contents(para_id, relay_parent)?; + let horizontal_messages = relay_chain_interface + .retrieve_all_inbound_hrmp_channel_contents(para_id, relay_parent)?; Some(ParachainInherentData { downward_messages, @@ -221,24 +136,6 @@ impl ParachainInherentData { relay_chain_state, }) } - - /// Create the [`ParachainInherentData`] at the given `relay_parent`. - /// - /// Returns `None` if the creation failed. - pub fn create_at_with_client( - relay_parent: PHash, - polkadot_client: &Client, - relay_chain_backend: &impl Backend, - validation_data: &PersistedValidationData, - para_id: ParaId, - ) -> Option { - polkadot_client.execute_with(CreateAtWithClient { - relay_chain_backend, - validation_data, - para_id, - relay_parent, - }) - } } #[async_trait::async_trait] @@ -258,35 +155,3 @@ impl sp_inherents::InherentDataProvider for ParachainInherentData { None } } - -/// Special structure to run [`ParachainInherentData::create_at`] with a [`Client`]. -struct CreateAtWithClient<'a, B> { - relay_parent: PHash, - relay_chain_backend: &'a B, - validation_data: &'a PersistedValidationData, - para_id: ParaId, -} - -impl<'a, B> ExecuteWithClient for CreateAtWithClient<'a, B> -where - B: Backend, -{ - type Output = Option; - - fn execute_with_client( - self, - client: std::sync::Arc, - ) -> Self::Output - where - Client: ProvideRuntimeApi, - Client::Api: ParachainHost, - { - ParachainInherentData::create_at( - self.relay_parent, - &*client, - self.relay_chain_backend, - self.validation_data, - self.para_id, - ) - } -} diff --git a/primitives/parachain-inherent/src/lib.rs b/primitives/parachain-inherent/src/lib.rs index e61a794c2f..4781f5e708 100644 --- a/primitives/parachain-inherent/src/lib.rs +++ b/primitives/parachain-inherent/src/lib.rs @@ -28,6 +28,7 @@ #![cfg_attr(not(feature = "std"), no_std)] use cumulus_primitives_core::{ + relay_chain::{BlakeTwo256, Hash as RelayHash, HashT as _}, InboundDownwardMessage, InboundHrmpMessage, ParaId, PersistedValidationData, }; @@ -42,7 +43,7 @@ pub use client_side::*; #[cfg(feature = "std")] mod mock; #[cfg(feature = "std")] -pub use mock::MockValidationDataInherentDataProvider; +pub use mock::{MockValidationDataInherentDataProvider, MockXcmConfig}; /// The identifier for the parachain inherent. pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"sysi1337"; @@ -68,3 +69,50 @@ pub struct ParachainInherentData { /// this means `sent_at` is **strictly** greater than the previous one (if any). pub horizontal_messages: BTreeMap>, } + +/// This struct provides ability to extend a message queue chain (MQC) and compute a new head. +/// +/// MQC is an instance of a [hash chain] applied to a message queue. Using a hash chain it's +/// possible to represent a sequence of messages using only a single hash. +/// +/// A head for an empty chain is agreed to be a zero hash. +/// +/// An instance is used to track either DMP from the relay chain or HRMP across a channel. +/// But a given instance is never used to track both. Therefore, you should call either +/// `extend_downward` or `extend_hrmp`, but not both methods on a single instance. +/// +/// [hash chain]: https://en.wikipedia.org/wiki/Hash_chain +#[derive(Default, Clone, codec::Encode, codec::Decode, scale_info::TypeInfo)] +pub struct MessageQueueChain(RelayHash); + +impl MessageQueueChain { + /// Extend the hash chain with an HRMP message. This method should be used only when + /// this chain is tracking HRMP. + pub fn extend_hrmp(&mut self, horizontal_message: &InboundHrmpMessage) -> &mut Self { + let prev_head = self.0; + self.0 = BlakeTwo256::hash_of(&( + prev_head, + horizontal_message.sent_at, + BlakeTwo256::hash_of(&horizontal_message.data), + )); + self + } + + /// Extend the hash chain with a downward message. This method should be used only when + /// this chain is tracking DMP. + pub fn extend_downward(&mut self, downward_message: &InboundDownwardMessage) -> &mut Self { + let prev_head = self.0; + self.0 = BlakeTwo256::hash_of(&( + prev_head, + downward_message.sent_at, + BlakeTwo256::hash_of(&downward_message.msg), + )); + self + } + + /// Return the current mead of the message queue hash chain. + /// This is agreed to be the zero hash for an empty chain. + pub fn head(&self) -> RelayHash { + self.0 + } +} diff --git a/primitives/parachain-inherent/src/mock.rs b/primitives/parachain-inherent/src/mock.rs index 4bb341ff0f..e69b0a8091 100644 --- a/primitives/parachain-inherent/src/mock.rs +++ b/primitives/parachain-inherent/src/mock.rs @@ -15,8 +15,16 @@ // along with Cumulus. If not, see . use crate::{ParachainInherentData, INHERENT_IDENTIFIER}; -use cumulus_primitives_core::PersistedValidationData; +use codec::Decode; +use cumulus_primitives_core::{ + relay_chain, InboundDownwardMessage, InboundHrmpMessage, ParaId, PersistedValidationData, +}; +use sc_client_api::{Backend, StorageProvider}; +use sp_api::BlockId; +use sp_core::twox_128; use sp_inherents::{InherentData, InherentDataProvider}; +use sp_runtime::traits::Block; +use std::collections::BTreeMap; use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder; @@ -29,6 +37,11 @@ use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder; /// relay_block_number = offset + relay_blocks_per_para_block * current_para_block /// To simulate a parachain that starts in relay block 1000 and gets a block in every other relay /// block, use 1000 and 2 +/// +/// Optionally, mock XCM messages can be injected into the runtime. When mocking XCM, +/// in addition to the messages themselves, you must provide some information about +/// your parachain's configuration in order to mock the MQC heads properly. +/// See [`MockXcmConfig`] for more information pub struct MockValidationDataInherentDataProvider { /// The current block number of the local block chain (the parachain) pub current_para_block: u32, @@ -38,6 +51,82 @@ pub struct MockValidationDataInherentDataProvider { /// The number of relay blocks that elapses between each parablock. Probably set this to 1 or 2 /// to simulate optimistic or realistic relay chain behavior. pub relay_blocks_per_para_block: u32, + /// XCM messages and associated configuration information. + pub xcm_config: MockXcmConfig, + /// Inbound downward XCM messages to be injected into the block. + pub raw_downward_messages: Vec>, + // Inbound Horizontal messages sorted by channel + pub raw_horizontal_messages: Vec<(ParaId, Vec)>, +} + +/// Parameters for how the Mock inherent data provider should inject XCM messages. +/// In addition to the messages themselves, some information about the parachain's +/// configuration is also required so that the MQC heads can be read out of the +/// parachain's storage, and the corresponding relay data mocked. +#[derive(Default)] +pub struct MockXcmConfig { + /// The parachain id of the parachain being mocked. + pub para_id: ParaId, + /// The starting state of the dmq_mqc_head. + pub starting_dmq_mqc_head: relay_chain::Hash, + /// The starting state of each parachain's mqc head + pub starting_hrmp_mqc_heads: BTreeMap, +} + +/// The name of the parachain system in the runtime. +/// +/// This name is used by frame to prefix storage items and will be required to read data from the storage. +/// +/// The `Default` implementation sets the name to `ParachainSystem`. +pub struct ParachainSystemName(pub Vec); + +impl Default for ParachainSystemName { + fn default() -> Self { + Self(b"ParachainSystem".to_vec()) + } +} + +impl MockXcmConfig { + /// Create a MockXcmConfig by reading the mqc_heads directly + /// from the storage of a previous block. + pub fn new, C: StorageProvider>( + client: &C, + parent_block: B::Hash, + para_id: ParaId, + parachain_system_name: ParachainSystemName, + ) -> Self { + let starting_dmq_mqc_head = client + .storage( + &BlockId::Hash(parent_block), + &sp_storage::StorageKey( + [twox_128(¶chain_system_name.0), twox_128(b"LastDmqMqcHead")] + .concat() + .to_vec(), + ), + ) + .expect("We should be able to read storage from the parent block.") + .map(|ref mut raw_data| { + Decode::decode(&mut &raw_data.0[..]).expect("Stored data should decode correctly") + }) + .unwrap_or_default(); + + let starting_hrmp_mqc_heads = client + .storage( + &BlockId::Hash(parent_block), + &sp_storage::StorageKey( + [twox_128(¶chain_system_name.0), twox_128(b"LastHrmpMqcHeads")] + .concat() + .to_vec(), + ), + ) + .expect("We should be able to read storage from the parent block.") + .map(|ref mut raw_data| { + Decode::decode(&mut &raw_data.0[..]).expect("Stored data should decode correctly") + }) + .unwrap_or_default(); + + Self { para_id, starting_dmq_mqc_head, starting_hrmp_mqc_heads } + } } #[async_trait::async_trait] @@ -46,27 +135,65 @@ impl InherentDataProvider for MockValidationDataInherentDataProvider { &self, inherent_data: &mut InherentData, ) -> Result<(), sp_inherents::Error> { - // Use the "sproof" (spoof proof) builder to build valid mock state root and proof. - let (relay_storage_root, proof) = - RelayStateSproofBuilder::default().into_state_root_and_proof(); - // Calculate the mocked relay block based on the current para block let relay_parent_number = self.relay_offset + self.relay_blocks_per_para_block * self.current_para_block; - let data = ParachainInherentData { - validation_data: PersistedValidationData { - parent_head: Default::default(), - relay_parent_storage_root: relay_storage_root, - relay_parent_number, - max_pov_size: Default::default(), - }, - downward_messages: Default::default(), - horizontal_messages: Default::default(), - relay_chain_state: proof, - }; + // Use the "sproof" (spoof proof) builder to build valid mock state root and proof. + let mut sproof_builder = RelayStateSproofBuilder::default(); + sproof_builder.para_id = self.xcm_config.para_id; - inherent_data.put_data(INHERENT_IDENTIFIER, &data) + // Process the downward messages and set up the correct head + let mut downward_messages = Vec::new(); + let mut dmq_mqc = crate::MessageQueueChain(self.xcm_config.starting_dmq_mqc_head); + for msg in &self.raw_downward_messages { + let wrapped = InboundDownwardMessage { sent_at: relay_parent_number, msg: msg.clone() }; + + dmq_mqc.extend_downward(&wrapped); + downward_messages.push(wrapped); + } + sproof_builder.dmq_mqc_head = Some(dmq_mqc.head()); + + // Process the hrmp messages and set up the correct heads + // Begin by collecting them into a Map + let mut horizontal_messages = BTreeMap::>::new(); + for (para_id, msg) in &self.raw_horizontal_messages { + let wrapped = InboundHrmpMessage { sent_at: relay_parent_number, data: msg.clone() }; + + horizontal_messages.entry(*para_id).or_default().push(wrapped); + } + + // Now iterate again, updating the heads as we go + for (para_id, messages) in &horizontal_messages { + let mut channel_mqc = crate::MessageQueueChain( + *self + .xcm_config + .starting_hrmp_mqc_heads + .get(para_id) + .unwrap_or(&relay_chain::Hash::default()), + ); + for message in messages { + channel_mqc.extend_hrmp(message); + } + sproof_builder.upsert_inbound_channel(*para_id).mqc_head = Some(channel_mqc.head()); + } + + let (relay_parent_storage_root, proof) = sproof_builder.into_state_root_and_proof(); + + inherent_data.put_data( + INHERENT_IDENTIFIER, + &ParachainInherentData { + validation_data: PersistedValidationData { + parent_head: Default::default(), + relay_parent_storage_root, + relay_parent_number, + max_pov_size: Default::default(), + }, + downward_messages, + horizontal_messages, + relay_chain_state: proof, + }, + ) } // Copied from the real implementation diff --git a/primitives/timestamp/Cargo.toml b/primitives/timestamp/Cargo.toml index e3404261cb..9dd8a3b329 100644 --- a/primitives/timestamp/Cargo.toml +++ b/primitives/timestamp/Cargo.toml @@ -2,7 +2,7 @@ name = "cumulus-primitives-timestamp" version = "0.1.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" description = "Provides timestamp related functionality for parachains." [dependencies] diff --git a/primitives/utility/Cargo.toml b/primitives/utility/Cargo.toml index 446af89907..41cfa53a32 100644 --- a/primitives/utility/Cargo.toml +++ b/primitives/utility/Cargo.toml @@ -2,7 +2,7 @@ name = "cumulus-primitives-utility" version = "0.1.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" [dependencies] # Substrate dependencies diff --git a/scripts/changelog/.gitignore b/scripts/changelog/.gitignore new file mode 100644 index 0000000000..4fbcc523b0 --- /dev/null +++ b/scripts/changelog/.gitignore @@ -0,0 +1,4 @@ +changelog.md +*.json +release*.md +.env diff --git a/scripts/changelog/Gemfile b/scripts/changelog/Gemfile new file mode 100644 index 0000000000..f2d7c3bd71 --- /dev/null +++ b/scripts/changelog/Gemfile @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +source 'https://rubygems.org' + +git_source(:github) { |repo_name| "https://github.com/#{repo_name}" } + +gem 'octokit', '~> 4' + +gem 'git_diff_parser', '~> 3' + +gem 'toml', '~> 0.3.0' + +gem 'rake', group: :dev + +gem 'optparse', '~> 0.1.1' + +gem 'logger', '~> 1.4' + +gem 'test-unit', group: :dev + +gem 'rubocop', group: :dev, require: false diff --git a/scripts/changelog/Gemfile.lock b/scripts/changelog/Gemfile.lock new file mode 100644 index 0000000000..855d7f91a5 --- /dev/null +++ b/scripts/changelog/Gemfile.lock @@ -0,0 +1,79 @@ +GEM + remote: https://rubygems.org/ + specs: + addressable (2.8.0) + public_suffix (>= 2.0.2, < 5.0) + ast (2.4.2) + faraday (1.8.0) + faraday-em_http (~> 1.0) + faraday-em_synchrony (~> 1.0) + faraday-excon (~> 1.1) + faraday-httpclient (~> 1.0.1) + faraday-net_http (~> 1.0) + faraday-net_http_persistent (~> 1.1) + faraday-patron (~> 1.0) + faraday-rack (~> 1.0) + multipart-post (>= 1.2, < 3) + ruby2_keywords (>= 0.0.4) + faraday-em_http (1.0.0) + faraday-em_synchrony (1.0.0) + faraday-excon (1.1.0) + faraday-httpclient (1.0.1) + faraday-net_http (1.0.1) + faraday-net_http_persistent (1.2.0) + faraday-patron (1.0.0) + faraday-rack (1.0.0) + git_diff_parser (3.2.0) + logger (1.4.4) + multipart-post (2.1.1) + octokit (4.21.0) + faraday (>= 0.9) + sawyer (~> 0.8.0, >= 0.5.3) + optparse (0.1.1) + parallel (1.21.0) + parser (3.0.2.0) + ast (~> 2.4.1) + parslet (2.0.0) + power_assert (2.0.1) + public_suffix (4.0.6) + rainbow (3.0.0) + rake (13.0.6) + regexp_parser (2.1.1) + rexml (3.2.5) + rubocop (1.23.0) + parallel (~> 1.10) + parser (>= 3.0.0.0) + rainbow (>= 2.2.2, < 4.0) + regexp_parser (>= 1.8, < 3.0) + rexml + rubocop-ast (>= 1.12.0, < 2.0) + ruby-progressbar (~> 1.7) + unicode-display_width (>= 1.4.0, < 3.0) + rubocop-ast (1.13.0) + parser (>= 3.0.1.1) + ruby-progressbar (1.11.0) + ruby2_keywords (0.0.5) + sawyer (0.8.2) + addressable (>= 2.3.5) + faraday (> 0.8, < 2.0) + test-unit (3.5.1) + power_assert + toml (0.3.0) + parslet (>= 1.8.0, < 3.0.0) + unicode-display_width (2.1.0) + +PLATFORMS + x86_64-darwin-20 + +DEPENDENCIES + git_diff_parser (~> 3) + logger (~> 1.4) + octokit (~> 4) + optparse (~> 0.1.1) + rake + rubocop + test-unit + toml (~> 0.3.0) + +BUNDLED WITH + 2.2.22 diff --git a/scripts/changelog/README.md b/scripts/changelog/README.md new file mode 100644 index 0000000000..7226530c42 --- /dev/null +++ b/scripts/changelog/README.md @@ -0,0 +1,71 @@ +# Changelog + +Currently, the changelog is built locally. It will be moved to CI once labels stabilize. + +For now, a bit of preparation is required before you can run the script: +- fetch the srtool digests +- store them under the `digests` folder as `-srtool-digest.json` +- ensure the `.env` file is up to date with correct information + +The content of the release notes is generated from the template files under the `scripts/changelog/templates` folder. For readability and maintenance, the template is split into several small snippets. + +Run: +``` +./bin/changelog [=HEAD] +``` + +For instance: +``` +./bin/changelog statemine-v5.0.0 +``` + +A file called `release-notes.md` will be generated and can be used for the release. + +## ENV + +You may use the following ENV for testing: + +``` +RUSTC_STABLE="rustc 1.56.1 (59eed8a2a 2021-11-01)" +RUSTC_NIGHTLY="rustc 1.57.0-nightly (51e514c0f 2021-09-12)" +PRE_RELEASE=true +HIDE_SRTOOL_ROCOCO=true +HIDE_SRTOOL_SHELL=true +REF1=statemine-v5.0.0 +REF2=HEAD +DEBUG=1 +NO_CACHE=1 +``` +## Considered labels + +The following list will likely evolve over time and it will be hard to keep it in sync. +In any case, if you want to find all the labels that are used, search for `meta` in the templates. +Currently, the considered labels are: + +- Priority: C labels +- Audit: D labels +- E4 => new host function +- B0 => silent, not showing up +- B1-releasenotes (misc unless other labels) +- B5-client (client changes) +- B7-runtimenoteworthy (runtime changes) +- T6-XCM + +Note that labels with the same letter are mutually exclusive. +A PR should not have both `B0` and `B5`, or both `C1` and `C9`. In case of conflicts, the template will +decide which label will be considered. + +## Dev and debuggin + +### Hot Reload + +The following command allows **Hot Reload**: +``` +fswatch templates -e ".*\.md$" | xargs -n1 -I{} ./bin/changelog statemine-v5.0.0 +``` +### Caching + +By default, if the changelog data from Github is already present, the calls to the Github API will be skipped +and the local version of the data will be used. This is much faster. +If you know that some labels have changed in Github, you probably want to refresh the data. +You can then either delete manually the `cumulus.json` file or `export NO_CACHE=1` to force refreshing the data. diff --git a/scripts/changelog/bin/changelog b/scripts/changelog/bin/changelog new file mode 100755 index 0000000000..33650787e1 --- /dev/null +++ b/scripts/changelog/bin/changelog @@ -0,0 +1,116 @@ +#!/usr/bin/env ruby + +# frozen_string_literal: true + +# call for instance as: +# ./bin/changelog statemine-v5.0.0 +# +# You may set the ENV NO_CACHE to force fetching from Github +# You should also ensure you set the ENV: GITHUB_TOKEN + +require_relative '../lib/changelog' +require 'logger' + +logger = Logger.new($stdout) +logger.level = Logger::DEBUG +logger.debug('Starting') + +owner = 'paritytech' +repo = 'cumulus' +ref1 = ARGV[0] +ref2 = ARGV[1] || 'HEAD' +output = ARGV[2] || 'release-notes.md' + +ENV['REF1'] = ref1 +ENV['REF2'] = ref2 + +gh_cumulus = SubRef.new(format('%s/%s', { owner: owner, repo: repo })) + +polkadot_ref1 = gh_cumulus.get_dependency_reference(ref1, 'polkadot-client') +polkadot_ref2 = gh_cumulus.get_dependency_reference(ref2, 'polkadot-client') + +substrate_ref1 = gh_cumulus.get_dependency_reference(ref1, 'sp-io') +substrate_ref2 = gh_cumulus.get_dependency_reference(ref2, 'sp-io') + +logger.debug("Polkadot from: #{polkadot_ref1}") +logger.debug("Polkadot to: #{polkadot_ref2}") + +logger.debug("Substrate from: #{substrate_ref1}") +logger.debug("Substrate to: #{substrate_ref2}") + +cumulus_data = 'cumulus.json' +substrate_data = 'substrate.json' +polkadot_data = 'polkadot.json' + +logger.debug("Using CUMULUS: #{cumulus_data}") +logger.debug("Using SUBSTRATE: #{substrate_data}") +logger.debug("Using POLKADOT: #{polkadot_data}") + +logger.warn('NO_CACHE set') if ENV['NO_CACHE'] + +# This is acting as cache so we don't spend time querying while testing +if ENV['NO_CACHE'] || !File.file?(cumulus_data) + logger.debug(format('Fetching data for Cumulus into %s', cumulus_data)) + cmd = format('changelogerator %s/%s -f %s -t %s > %s', + { owner: owner, repo: repo, from: ref1, to: ref2, output: cumulus_data }) + system(cmd) +else + logger.debug("Re-using:#{cumulus_data}") +end + +if ENV['NO_CACHE'] || !File.file?(polkadot_data) + logger.debug(format('Fetching data for Polkadot into %s', polkadot_data)) + cmd = format('changelogerator %s/%s -f %s -t %s > %s', + { owner: owner, repo: 'polkadot', from: polkadot_ref1, to: polkadot_ref2, output: polkadot_data }) + system(cmd) +else + logger.debug("Re-using:#{polkadot_data}") +end + +if ENV['NO_CACHE'] || !File.file?(substrate_data) + logger.debug(format('Fetching data for Substrate into %s', substrate_data)) + cmd = format('changelogerator %s/%s -f %s -t %s > %s', + { owner: owner, repo: 'substrate', from: substrate_ref1, to: substrate_ref2, output: substrate_data }) + system(cmd) +else + logger.debug("Re-using:#{substrate_data}") +end + +SHELL_DIGEST = ENV['SHELL_DIGEST'] || 'digests/shell-srtool-digest.json' +WESTMINT_DIGEST = ENV['WESTMINT_DIGEST'] || 'digests/westmint-srtool-digest.json' +STATEMINE_DIGEST = ENV['STATEMINE_DIGEST'] || 'digests/statemine-srtool-digest.json' +STATEMINT_DIGEST = ENV['STATEMINT_DIGEST'] || 'digests/statemint-srtool-digest.json' +ROCOCO_PARA_DIGEST = ENV['ROCOCO_PARA_DIGEST'] || 'digests/rococo-parachain-srtool-digest.json' + +# Here we compose all the pieces together into one +# single big json file. +cmd = format('jq \ + --slurpfile cumulus %s \ + --slurpfile substrate %s \ + --slurpfile polkadot %s \ + --slurpfile srtool_shell %s \ + --slurpfile srtool_westmint %s \ + --slurpfile srtool_statemine %s \ + --slurpfile srtool_statemint %s \ + --slurpfile srtool_rococo_parachain %s \ + -n \'{ + cumulus: $cumulus[0], + substrate: $substrate[0], + polkadot: $polkadot[0], + srtool: [ + { name: "rococo", data: $srtool_rococo_parachain[0] }, + { name: "shell", data: $srtool_shell[0] }, + { name: "westmint", data: $srtool_westmint[0] }, + { name: "statemint", data: $srtool_statemint[0] }, + { name: "statemine", data: $srtool_statemine[0] } + ] }\' > context.json', cumulus_data, substrate_data, polkadot_data, + SHELL_DIGEST, + WESTMINT_DIGEST, + STATEMINE_DIGEST, + STATEMINT_DIGEST, + ROCOCO_PARA_DIGEST) +system(cmd) + +cmd = format('tera --env --env-key env --include-path templates \ + --template templates/template.md.tera context.json > %s', output) +system(cmd) diff --git a/scripts/changelog/digests/.gitignore b/scripts/changelog/digests/.gitignore new file mode 100644 index 0000000000..a6c57f5fb2 --- /dev/null +++ b/scripts/changelog/digests/.gitignore @@ -0,0 +1 @@ +*.json diff --git a/scripts/changelog/digests/.gitkeep b/scripts/changelog/digests/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/scripts/changelog/lib/changelog.rb b/scripts/changelog/lib/changelog.rb new file mode 100644 index 0000000000..2d9ee29a8c --- /dev/null +++ b/scripts/changelog/lib/changelog.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +# A Class to find Substrate references +class SubRef + require 'octokit' + require 'toml' + + attr_reader :client, :repository + + def initialize(github_repo) + @client = Octokit::Client.new( + access_token: ENV['GITHUB_TOKEN'] + ) + @repository = @client.repository(github_repo) + end + + # This function checks the Cargo.lock of a given + # Rust project, for a given package, and fetches + # the dependency git ref. + def get_dependency_reference(ref, package) + cargo = TOML::Parser.new( + Base64.decode64( + @client.contents( + @repository.full_name, + path: 'Cargo.lock', + query: { ref: ref.to_s } + ).content + ) + ).parsed + cargo['package'].find { |p| p['name'] == package }['source'].split('#').last + end +end diff --git a/scripts/changelog/templates/change.md.tera b/scripts/changelog/templates/change.md.tera new file mode 100644 index 0000000000..7a4c9a357c --- /dev/null +++ b/scripts/changelog/templates/change.md.tera @@ -0,0 +1,45 @@ +{# This macro shows ONE change #} +{%- macro change(c, cml="[C]", dot="[P]", sub="[S]") -%} + +{%- if c.meta.C and c.meta.C.value >= 7 -%} +{%- set prio = " ‼️ HIGH" -%} +{%- elif c.meta.C and c.meta.C.value >= 5 -%} +{%- set prio = " ❗️ Medium" -%} +{%- elif c.meta.C and c.meta.C.value >= 3 -%} +{%- set prio = " Low" -%} +{%- else -%} +{%- set prio = "" -%} +{%- endif -%} + +{%- set audit = "" -%} +{# +{%- if c.meta.D and c.meta.D.value == 1 -%} +{%- set audit = "✅ audited " -%} +{%- elif c.meta.D and c.meta.D.value == 2 -%} +{%- set audit = "✅ trivial " -%} +{%- elif c.meta.D and c.meta.D.value == 3 -%} +{%- set audit = "✅ trivial " -%} +{%- elif c.meta.D and c.meta.D.value == 5 -%} +{%- set audit = "⏳ pending non-critical audit " -%} +{%- else -%} +{%- set audit = "" -%} +{%- endif -%} +#} + +{%- if c.html_url is containing("polkadot") -%} +{%- set repo = dot -%} +{%- elif c.html_url is containing("cumulus") -%} +{%- set repo = cml -%} +{%- elif c.html_url is containing("substrate") -%} +{%- set repo = sub -%} +{%- else -%} +{%- set repo = " " -%} +{%- endif -%} + +{%- if c.meta.T and c.meta.T.value == 6 -%} +{%- set xcm = " [✉️ XCM]" -%} +{%- else -%} +{%- set xcm = "" -%} +{%- endif -%} +{{- repo }} {{ audit }}[`#{{c.number}}`]({{c.html_url}}) {{- prio }} - {{ c.title | capitalize | truncate(length=60, end="…") }}{{xcm }} +{%- endmacro change -%} diff --git a/scripts/changelog/templates/changes.md.tera b/scripts/changelog/templates/changes.md.tera new file mode 100644 index 0000000000..4a84608819 --- /dev/null +++ b/scripts/changelog/templates/changes.md.tera @@ -0,0 +1,14 @@ +{# This include generates the section showing the changes #} +## Changes + +### Legend + +- {{ CML }} Cumulus +- {{ DOT }} Polkadot +- {{ SUB }} Substrate + +{% include "changes_client.md.tera" %} + +{% include "changes_runtime.md.tera" %} + +{% include "changes_misc.md.tera" %} diff --git a/scripts/changelog/templates/changes_client.md.tera b/scripts/changelog/templates/changes_client.md.tera new file mode 100644 index 0000000000..36fb6b9de6 --- /dev/null +++ b/scripts/changelog/templates/changes_client.md.tera @@ -0,0 +1,17 @@ +{% import "change.md.tera" as m_c -%} +### Client + +{#- The changes are sorted by merge date #} +{%- for pr in changes | sort(attribute="merged_at") %} + +{%- if pr.meta.B %} + {%- if pr.meta.B.value == 0 %} + {#- We skip silent ones -#} + {%- else -%} + + {%- if pr.meta.B.value == 5 and not pr.title is containing("ompanion") %} +- {{ m_c::change(c=pr) }} + {%- endif -%} + {% endif -%} + {% endif -%} +{% endfor %} diff --git a/scripts/changelog/templates/changes_misc.md.tera b/scripts/changelog/templates/changes_misc.md.tera new file mode 100644 index 0000000000..7585eb8bc5 --- /dev/null +++ b/scripts/changelog/templates/changes_misc.md.tera @@ -0,0 +1,39 @@ +{%- import "change.md.tera" as m_c -%} + +{%- set_global misc_count = 0 -%} +{#- First pass to count #} +{%- for pr in changes -%} + {%- if pr.meta.B %} + {%- if pr.meta.B.value == 0 -%} + {#- We skip silent ones -#} + {%- else -%} + {%- if pr.meta.B and pr.meta.B.value != 5 and pr.meta.B.value != 7 or pr.meta.C or not pr.meta.B %} +{%- set_global misc_count = misc_count + 1 -%} + {%- endif -%} + {% endif -%} + {% endif -%} +{% endfor %} + +### Misc + +{% if misc_count > 10 %} +There are other misc. changes. You can expand the list below to view them all. +
Other misc. changes +{% endif -%} + +{#- The changes are sorted by merge date #} +{%- for pr in changes | sort(attribute="merged_at") %} + {%- if pr.meta.B and not pr.title is containing("ompanion") %} + {%- if pr.meta.B.value == 0 %} + {#- We skip silent ones -#} + {%- else -%} + {%- if pr.meta.B and pr.meta.B.value != 5 and pr.meta.B.value != 7 or pr.meta.C or not pr.meta.B %} +- {{ m_c::change(c=pr) }} + {%- endif -%} + {% endif -%} + {% endif -%} +{% endfor %} + +{% if misc_count > 10 %} +
+{% endif -%} diff --git a/scripts/changelog/templates/changes_runtime.md.tera b/scripts/changelog/templates/changes_runtime.md.tera new file mode 100644 index 0000000000..67da1ebbc3 --- /dev/null +++ b/scripts/changelog/templates/changes_runtime.md.tera @@ -0,0 +1,19 @@ +{%- import "change.md.tera" as m_c -%} + +### Runtime + +{#- The changes are sorted by merge date -#} +{% for pr in changes | sort(attribute="merged_at") -%} + +{%- if pr.meta.B -%} +{%- if pr.meta.B.value == 0 -%} +{#- We skip silent ones -#} +{%- else -%} + +{%- if pr.meta.B.value == 7 and not pr.title is containing("ompanion") %} +- {{ m_c::change(c=pr) }} +{%- endif -%} +{%- endif -%} + +{%- endif -%} +{%- endfor %} diff --git a/scripts/changelog/templates/compiler.md.tera b/scripts/changelog/templates/compiler.md.tera new file mode 100644 index 0000000000..0420a88c39 --- /dev/null +++ b/scripts/changelog/templates/compiler.md.tera @@ -0,0 +1,6 @@ +## Rust compiler versions + +This release was tested against the following versions of `rustc`. Other versions may work. + +- Rust Stable: `{{ env.RUSTC_STABLE }}` +- Rust Nightly: `{{ env.RUSTC_NIGHTLY }}` diff --git a/scripts/changelog/templates/debug.md.tera b/scripts/changelog/templates/debug.md.tera new file mode 100644 index 0000000000..29ac673a39 --- /dev/null +++ b/scripts/changelog/templates/debug.md.tera @@ -0,0 +1,10 @@ +{%- set to_ignore = changes | filter(attribute="meta.B.value", value=0) %} + + diff --git a/scripts/changelog/templates/docker_image.md.tera b/scripts/changelog/templates/docker_image.md.tera new file mode 100644 index 0000000000..59f631106b --- /dev/null +++ b/scripts/changelog/templates/docker_image.md.tera @@ -0,0 +1,11 @@ + diff --git a/scripts/changelog/templates/global_priority.md.tera b/scripts/changelog/templates/global_priority.md.tera new file mode 100644 index 0000000000..f8e2d8ddea --- /dev/null +++ b/scripts/changelog/templates/global_priority.md.tera @@ -0,0 +1,37 @@ +{% import "high_priority.md.tera" as m_p -%} +## Global Priority + +{%- set cumulus_prio = 0 -%} +{%- set polkadot_prio = 0 -%} +{%- set substrate_prio = 0 -%} + +{# We fetch the various priorities #} +{%- if cumulus.meta.C -%} + {%- set cumulus_prio = cumulus.meta.C.max -%} +{%- endif -%} +{%- if polkadot.meta.C -%} + {%- set polkadot_prio = polkadot.meta.C.max -%} +{%- endif -%} +{%- if substrate.meta.C -%} + {%- set substrate_prio = substrate.meta.C.max -%} +{%- endif -%} + +{# We compute the global priority #} +{%- set global_prio = cumulus_prio -%} +{%- if polkadot_prio > global_prio -%} + {% set global_prio = polkadot_prio -%} +{%- endif -%} +{%- if substrate_prio > global_prio -%} + {%- set global_prio = substrate_prio -%} +{%- endif -%} + +{# We show the result #} +{{ m_p::high_priority(p=global_prio, changes=changes) }} + + + +{# todo: show high prio list here #} diff --git a/scripts/changelog/templates/high_priority.md.tera b/scripts/changelog/templates/high_priority.md.tera new file mode 100644 index 0000000000..f773fa7a9e --- /dev/null +++ b/scripts/changelog/templates/high_priority.md.tera @@ -0,0 +1,37 @@ +{%- import "change.md.tera" as m_c -%} + +{# This macro convert a priority level into readable output #} +{%- macro high_priority(p, changes) -%} + +{%- if p >= 7 -%} + {%- set prio = "‼️ HIGH" -%} + {%- set text = "This is a **high priority** release and you must upgrade as as soon as possible." -%} +{%- elif p >= 5 -%} + {%- set prio = "❗️ Medium" -%} + {%- set text = "This is a medium priority release and you should upgrade in a timely manner." -%} +{%- elif p >= 3 -%} + {%- set prio = "Low" -%} + {%- set text = "This is a low priority release and you may upgrade at your convenience." -%} +{%- endif %} + +{%- if prio %} +{{prio}}: {{text}} +{%- else -%} + +{% endif %} + +The changes motivating this priority level are: + +{% for pr in changes | sort(attribute="merged_at") -%} + {%- if pr.meta.C -%} + {%- if pr.meta.C.value == p %} +- {{ m_c::change(c=pr) }} +{%- if pr.meta.B and pr.meta.B.value == 7 %} +(RUNTIME) +{% endif %} + {%- endif -%} + {%- endif -%} +{%- endfor %} + + +{%- endmacro priority -%} diff --git a/scripts/changelog/templates/host_functions.md.tera b/scripts/changelog/templates/host_functions.md.tera new file mode 100644 index 0000000000..6cc4c7581a --- /dev/null +++ b/scripts/changelog/templates/host_functions.md.tera @@ -0,0 +1,30 @@ +{%- import "change.md.tera" as m_c -%} +{%- set_global host_fn_count = 0 -%} + +{% for pr in changes | sort(attribute="merged_at") -%} + +{%- if pr.meta.B and pr.meta.B.value == 0 -%} +{#- We skip silent ones -#} +{%- else -%} + {%- if pr.meta.E and pr.meta.E.value == 4 -%} + {%- set_global host_fn_count = host_fn_count + 1 -%} + - {{ m_c::change(c=pr) }} + {% endif -%} + {% endif -%} +{%- endfor -%} + + + +{% if host_fn_count == 0 -%} + +{% elif host_fn_count == 1 -%} +## Host functions + +⚠️ The runtimes in this release contain one new **host function**. + +⚠️ It is critical that you update your client before the chain switches to the new runtimes. +{%- else -%} +⚠️ The runtimes in this release contain {{ host_fn_count }} new **host function{{ host_fn_count | pluralize }}**. + +⚠️ It is critical that you update your client before the chain switches to the new runtimes. +{%- endif %} diff --git a/scripts/changelog/templates/migrations.md.tera b/scripts/changelog/templates/migrations.md.tera new file mode 100644 index 0000000000..af04821a2e --- /dev/null +++ b/scripts/changelog/templates/migrations.md.tera @@ -0,0 +1,14 @@ +{%- import "change.md.tera" as m_c %} + +## Migrations + +{% for pr in changes | sort(attribute="merged_at") -%} + +{%- if pr.meta.B and pr.meta.B.value == 0 %} +{#- We skip silent ones -#} +{%- else -%} +{%- if pr.meta.E and pr.meta.E.value == 1 -%} +- {{ m_c::change(c=pr) }} +{% endif -%} +{% endif -%} +{% endfor -%} diff --git a/scripts/changelog/templates/pre_release.md.tera b/scripts/changelog/templates/pre_release.md.tera new file mode 100644 index 0000000000..53a0e90654 --- /dev/null +++ b/scripts/changelog/templates/pre_release.md.tera @@ -0,0 +1,11 @@ +{%- if env.PRE_RELEASE == "true" -%} +
⚠️ This is a pre-release + +**Release candidates** are **pre-releases** may not be final. +Although they are reasonably tested, there may be additional changes or issues +before an official release is tagged. Use at your own discretion, and consider +only using published releases on critical production infrastructure. +
+{% else -%} + +{%- endif %} diff --git a/scripts/changelog/templates/runtime.md.tera b/scripts/changelog/templates/runtime.md.tera new file mode 100644 index 0000000000..f4afa78972 --- /dev/null +++ b/scripts/changelog/templates/runtime.md.tera @@ -0,0 +1,28 @@ +{# This macro shows one runtime #} +{%- macro runtime(runtime) -%} + +### {{ runtime.name | capitalize }} + +{%- if runtime.data.runtimes.compressed.subwasm.compression.compressed %} +{%- set compressed = "Yes" %} +{%- else %} +{%- set compressed = "No" %} +{%- endif %} + +{%- set comp_ratio = 100 - (runtime.data.runtimes.compressed.subwasm.compression.size_compressed / runtime.data.runtimes.compressed.subwasm.compression.size_decompressed *100) %} + + + + + +``` +🏋️ Runtime Size: {{ runtime.data.runtimes.compressed.subwasm.size | filesizeformat }} ({{ runtime.data.runtimes.compressed.subwasm.size }} bytes) +🔥 Core Version: {{ runtime.data.runtimes.compressed.subwasm.core_version }} +🗜 Compressed: {{ compressed }}: {{ comp_ratio | round(method="ceil", precision=2) }}% +🎁 Metadata version: V{{ runtime.data.runtimes.compressed.subwasm.metadata_version }} +🗳️ system.setCode hash: {{ runtime.data.runtimes.compressed.subwasm.proposal_hash }} +🗳️ authorizeUpgrade hash: {{ runtime.data.runtimes.compressed.subwasm.parachain_authorize_upgrade_hash }} +#️⃣ Blake2-256 hash: {{ runtime.data.runtimes.compressed.subwasm.blake2_256 }} +📦 IPFS: {{ runtime.data.runtimes.compressed.subwasm.ipfs_hash }} +``` +{%- endmacro runtime %} diff --git a/scripts/changelog/templates/runtimes.md.tera b/scripts/changelog/templates/runtimes.md.tera new file mode 100644 index 0000000000..600c5f17dc --- /dev/null +++ b/scripts/changelog/templates/runtimes.md.tera @@ -0,0 +1,17 @@ +{# This include shows the list and details of the runtimes #} +{%- import "runtime.md.tera" as m_r -%} + +## Runtimes + +{% set rtm = srtool[0] -%} + +The information about the runtimes included in this release can be found below. +The runtimes have been built using [{{ rtm.data.gen }}](https://github.com/paritytech/srtool) and `{{ rtm.data.rustc }}`. + +{%- for runtime in srtool | sort(attribute="name") %} +{%- set HIDE_VAR = "HIDE_SRTOOL_" ~ runtime.name | upper %} +{%- if not env is containing(HIDE_VAR) %} + +{{ m_r::runtime(runtime=runtime) }} +{%- endif %} +{%- endfor %} diff --git a/scripts/changelog/templates/template.md.tera b/scripts/changelog/templates/template.md.tera new file mode 100644 index 0000000000..5a1542e876 --- /dev/null +++ b/scripts/changelog/templates/template.md.tera @@ -0,0 +1,32 @@ +{# This is the entry point of the template -#} + +{% include "pre_release.md.tera" -%} + +{% if env.PRE_RELEASE == "true" -%} +This pre-release contains the changes from `{{ env.REF1 }}` to `{{ env.REF2 }}`. +{% else -%} +This release contains the changes from `{{ env.REF1 }}` to `{{ env.REF2 }}`. +{% endif -%} + +{%- set changes = cumulus.changes | concat(with=substrate.changes) -%} +{%- set changes = changes | concat(with=polkadot.changes) -%} +{%- include "debug.md.tera" -%} + +{%- set CML = "[C]" -%} +{%- set DOT = "[P]" -%} +{%- set SUB = "[S]" -%} + + +{% include "global_priority.md.tera" -%} + +{% include "host_functions.md.tera" -%} + +{% include "compiler.md.tera" -%} + +{% include "migrations.md.tera" -%} + +{% include "runtimes.md.tera" -%} + +{% include "changes.md.tera" -%} + +{% include "docker_image.md.tera" -%} diff --git a/scripts/changelog/test/test_basic.rb b/scripts/changelog/test/test_basic.rb new file mode 100755 index 0000000000..d099fadca4 --- /dev/null +++ b/scripts/changelog/test/test_basic.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +require_relative '../lib/changelog' +require 'test/unit' + +class TestChangelog < Test::Unit::TestCase + def test_get_dep_ref_polkadot + c = SubRef.new('paritytech/polkadot') + ref = '13c2695' + package = 'sc-cli' + result = c.get_dependency_reference(ref, package) + assert_equal('7db0768a85dc36a3f2a44d042b32f3715c00a90d', result) + end + + def test_get_dep_ref_invalid_ref + c = SubRef.new('paritytech/polkadot') + ref = '9999999' + package = 'sc-cli' + assert_raise do + c.get_dependency_reference(ref, package) + end + end +end diff --git a/scripts/common/lib.sh b/scripts/common/lib.sh new file mode 100644 index 0000000000..93e0392b3e --- /dev/null +++ b/scripts/common/lib.sh @@ -0,0 +1,141 @@ +#!/bin/sh + +api_base="https://api.github.com/repos" + +# Function to take 2 git tags/commits and get any lines from commit messages +# that contain something that looks like a PR reference: e.g., (#1234) +sanitised_git_logs(){ + git --no-pager log --pretty=format:"%s" "$1...$2" | + # Only find messages referencing a PR + grep -E '\(#[0-9]+\)' | + # Strip any asterisks + sed 's/^* //g' +} + +# Checks whether a tag on github has been verified +# repo: 'organization/repo' +# tagver: 'v1.2.3' +# Usage: check_tag $repo $tagver +check_tag () { + repo=$1 + tagver=$2 + if [ -n "$GITHUB_RELEASE_TOKEN" ]; then + echo '[+] Fetching tag using privileged token' + tag_out=$(curl -H "Authorization: token $GITHUB_RELEASE_TOKEN" -s "$api_base/$repo/git/refs/tags/$tagver") + else + echo '[+] Fetching tag using unprivileged token' + tag_out=$(curl -H "Authorization: token $GITHUB_PR_TOKEN" -s "$api_base/$repo/git/refs/tags/$tagver") + fi + tag_sha=$(echo "$tag_out" | jq -r .object.sha) + object_url=$(echo "$tag_out" | jq -r .object.url) + if [ "$tag_sha" = "null" ]; then + return 2 + fi + echo "[+] Tag object SHA: $tag_sha" + verified_str=$(curl -H "Authorization: token $GITHUB_RELEASE_TOKEN" -s "$object_url" | jq -r .verification.verified) + if [ "$verified_str" = "true" ]; then + # Verified, everything is good + return 0 + else + # Not verified. Bad juju. + return 1 + fi +} + +# Checks whether a given PR has a given label. +# repo: 'organization/repo' +# pr_id: 12345 +# label: B1-silent +# Usage: has_label $repo $pr_id $label +has_label(){ + repo="$1" + pr_id="$2" + label="$3" + + # These will exist if the function is called in Gitlab. + # If the function's called in Github, we should have GITHUB_ACCESS_TOKEN set + # already. + if [ -n "$GITHUB_RELEASE_TOKEN" ]; then + GITHUB_TOKEN="$GITHUB_RELEASE_TOKEN" + elif [ -n "$GITHUB_PR_TOKEN" ]; then + GITHUB_TOKEN="$GITHUB_PR_TOKEN" + fi + + out=$(curl -H "Authorization: token $GITHUB_TOKEN" -s "$api_base/$repo/pulls/$pr_id") + [ -n "$(echo "$out" | tr -d '\r\n' | jq ".labels | .[] | select(.name==\"$label\")")" ] +} + +github_label () { + echo + echo "# run github-api job for labeling it ${1}" + curl -sS -X POST \ + -F "token=${CI_JOB_TOKEN}" \ + -F "ref=master" \ + -F "variables[LABEL]=${1}" \ + -F "variables[PRNO]=${CI_COMMIT_REF_NAME}" \ + -F "variables[PROJECT]=paritytech/polkadot" \ + "${GITLAB_API}/projects/${GITHUB_API_PROJECT}/trigger/pipeline" +} + +# Formats a message into a JSON string for posting to Matrix +# message: 'any plaintext message' +# formatted_message: 'optional message formatted in html' +# Usage: structure_message $content $formatted_content (optional) +structure_message() { + if [ -z "$2" ]; then + body=$(jq -Rs --arg body "$1" '{"msgtype": "m.text", $body}' < /dev/null) + else + body=$(jq -Rs --arg body "$1" --arg formatted_body "$2" '{"msgtype": "m.text", $body, "format": "org.matrix.custom.html", $formatted_body}' < /dev/null) + fi + echo "$body" +} + +# Post a message to a matrix room +# body: '{body: "JSON string produced by structure_message"}' +# room_id: !fsfSRjgjBWEWffws:matrix.parity.io +# access_token: see https://matrix.org/docs/guides/client-server-api/ +# Usage: send_message $body (json formatted) $room_id $access_token +send_message() { +curl -XPOST -d "$1" "https://matrix.parity.io/_matrix/client/r0/rooms/$2/send/m.room.message?access_token=$3" +} + +# Pretty-printing functions +boldprint () { printf "|\n| \033[1m%s\033[0m\n|\n" "${@}"; } +boldcat () { printf "|\n"; while read -r l; do printf "| \033[1m%s\033[0m\n" "${l}"; done; printf "|\n" ; } + +skip_if_companion_pr() { + url="https://api.github.com/repos/paritytech/polkadot/pulls/${CI_COMMIT_REF_NAME}" + echo "[+] API URL: $url" + + pr_title=$(curl -sSL -H "Authorization: token ${GITHUB_PR_TOKEN}" "$url" | jq -r .title) + echo "[+] PR title: $pr_title" + + if echo "$pr_title" | grep -qi '^companion'; then + echo "[!] PR is a companion PR. Build is already done in substrate" + exit 0 + else + echo "[+] PR is not a companion PR. Proceeding test" + fi +} + +# Fetches the tag name of the latest release from a repository +# repo: 'organisation/repo' +# Usage: latest_release 'paritytech/polkadot' +latest_release() { + curl -s "$api_base/$1/releases/latest" | jq -r '.tag_name' +} + +# Check for runtime changes between two commits. This is defined as any changes +# to /primitives/src/* and any *production* chains under /runtime +has_runtime_changes() { + from=$1 + to=$2 + + if git diff --name-only "${from}...${to}" \ + | grep -q -e '^runtime/polkadot' -e '^runtime/kusama' -e '^primitives/src/' -e '^runtime/common' + then + return 0 + else + return 1 + fi +} diff --git a/scripts/create_seedling_spec.sh b/scripts/create_seedling_spec.sh new file mode 100755 index 0000000000..447afe92ae --- /dev/null +++ b/scripts/create_seedling_spec.sh @@ -0,0 +1,56 @@ +#!/usr/bin/env bash + +usage() { + echo Usage: + echo "$0 " + exit 1 +} + +set -e + +runtime_path=$1 +name=$2 +id="seedling-$3" +chain_type=$4 +bootnodes=$5 +relay_chain=$6 +para_id=$7 +sudo=$8 + +[ -z "$runtime_path" ] && usage +[ -z "$name" ] && usage +[ -z "$id" ] && usage +[ -z "$chain_type" ] && usage +[ -z "$bootnodes" ] && usage +[ -z "$relay_chain" ] && usage +[ -z "$para_$id" ] && usage +[ -z "$sudo" ] && usage + +binary="./target/release/polkadot-collator" + +# build the chain spec we'll manipulate +$binary build-spec --chain seedling > seedling-spec-plain.json + +# convert runtime to hex +cat $runtime_path | od -A n -v -t x1 | tr -d ' \n' > seedling-hex.txt + +# replace the runtime in the spec with the given runtime and set some values to production +cat seedling-spec-plain.json | jq --rawfile code seedling-hex.txt '.genesis.runtime.system.code = ("0x" + $code)' \ + | jq --arg name $name '.name = $name' \ + | jq --arg id $id '.id = $id' \ + | jq --arg chain_type $chain_type '.chainType = $chain_type' \ + | jq --argjson bootnodes $bootnodes '.bootNodes = $bootnodes' \ + | jq --arg relay_chain $relay_chain '.relay_chain = $relay_chain' \ + | jq --argjson para_id $para_id '.para_id = $para_id' \ + | jq --arg sudo $sudo '.genesis.runtime.sudo.key = $sudo' \ + | jq --argjson para_id $para_id '.genesis.runtime.parachainInfo.parachainId = $para_id' \ + > edited-seedling-plain.json + +# build a raw spec +$binary build-spec --chain edited-seedling-plain.json --raw > seedling-spec-raw.json + +# build genesis data +$binary export-genesis-state --parachain-id=$para_id --chain seedling-spec-raw.json > seedling-head-data + +# build genesis wasm +$binary export-genesis-wasm --chain seedling-spec-raw.json > seedling-wasm diff --git a/scripts/create_shell_spec.sh b/scripts/create_shell_spec.sh new file mode 100755 index 0000000000..de9348ef17 --- /dev/null +++ b/scripts/create_shell_spec.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash + +usage() { + echo Usage: + echo "$0 " + exit 1 +} + +set -e + +rt_path=$1 + +binary="./target/release/polkadot-collator" + +# build the chain spec we'll manipulate +$binary build-spec --chain shell > shell-spec-plain.json + +# convert runtime to hex +cat $rt_path | od -A n -v -t x1 | tr -d ' \n' > shell-hex.txt + +# replace the runtime in the spec with the given runtime and set some values to production +cat shell-spec-plain.json | jq --rawfile code shell-hex.txt '.genesis.runtime.system.code = ("0x" + $code)' \ + | jq '.name = "Shell"' \ + | jq '.id = "shell"' \ + | jq '.chainType = "Live"' \ + | jq '.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"]' \ + | jq '.relay_chain = "polkadot"' \ + > edited-shell-plain.json + +# build a raw spec +$binary build-spec --chain edited-shell-plain.json --raw > shell-spec-raw.json + +# build genesis data +$binary export-genesis-state --parachain-id=1000 --chain shell-spec-raw.json > shell-head-data + +# build genesis wasm +$binary export-genesis-wasm --chain shell-spec-raw.json > shell-wasm diff --git a/scripts/generate_genesis_value.sh b/scripts/generate_genesis_value.sh index 26b87ef81b..2d5289b292 100755 --- a/scripts/generate_genesis_value.sh +++ b/scripts/generate_genesis_value.sh @@ -15,3 +15,8 @@ yarn popd node generate_genesis_values ../polkadot-parachains/res/$chain_id.json ../polkadot-parachains/res/${chain_id}_genesis_values.json + +pushd scale_encode_genesis +yarn +popd +node scale_encode_genesis ../polkadot-parachains/res/${chain_id}_genesis_values.json ${chain_id}_genesis_values.txt diff --git a/scripts/generate_genesis_values/index.js b/scripts/generate_genesis_values/index.js index 24db27bb80..fffc41abec 100644 --- a/scripts/generate_genesis_values/index.js +++ b/scripts/generate_genesis_values/index.js @@ -45,10 +45,10 @@ fs.readFile(input, "utf8", (err, data) => { const spec = JSON.parse(data); - const genesis = Object.fromEntries( + const genesis = Object.entries(spec.genesis.raw.top).filter( ([key, value]) => !startsWith(key, filter_prefixes) - ) - ); + ); + fs.writeFileSync(output, JSON.stringify(genesis)); }); diff --git a/scripts/github/check_labels.sh b/scripts/github/check_labels.sh new file mode 100755 index 0000000000..12f07b3495 --- /dev/null +++ b/scripts/github/check_labels.sh @@ -0,0 +1,75 @@ +#!/usr/bin/env bash + +#shellcheck source=../common/lib.sh +source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )/../common/lib.sh" + +repo="$GITHUB_REPOSITORY" +pr="$GITHUB_PR" + +ensure_labels() { + for label in "$@"; do + if has_label "$repo" "$pr" "$label"; then + return 0 + fi + done + return 1 +} + +# Must have one of the following labels +releasenotes_labels=( + 'B0-silent' + 'B1-releasenotes' + 'B7-runtimenoteworthy' +) + +# Must be an ordered list of priorities, lowest first +priority_labels=( + 'C1-low 📌' + 'C3-medium 📣' + 'C7-high ❗️' + 'C9-critical ‼️' +) + +audit_labels=( + 'D1-audited 👍' + 'D2-notlive 💤' + 'D3-trivial 🧸' + 'D5-nicetohaveaudit ⚠️' + 'D9-needsaudit 👮' +) + +echo "[+] Checking release notes (B) labels for $CI_COMMIT_BRANCH" +if ensure_labels "${releasenotes_labels[@]}"; then + echo "[+] Release notes label detected. All is well." +else + echo "[!] Release notes label not detected. Please add one of: ${releasenotes_labels[*]}" + exit 1 +fi + +echo "[+] Checking release priority (C) labels for $CI_COMMIT_BRANCH" +if ensure_labels "${priority_labels[@]}"; then + echo "[+] Release priority label detected. All is well." +else + echo "[!] Release priority label not detected. Please add one of: ${priority_labels[*]}" + exit 1 +fi + +if has_runtime_changes "${BASE_SHA}" "${HEAD_SHA}"; then + echo "[+] Runtime changes detected. Checking audit (D) labels" + if ensure_labels "${audit_labels[@]}"; then + echo "[+] Release audit label detected. All is well." + else + echo "[!] Release audit label not detected. Please add one of: ${audit_labels[*]}" + exit 1 + fi +fi + +# If the priority is anything other than the lowest, we *must not* have a B0-silent +# label +if has_label "$repo" "$GITHUB_PR" 'B0-silent' && + ! has_label "$repo" "$GITHUB_PR" "${priority_labels[0]}"; then + echo "[!] Changes with a priority higher than C1-low *MUST* have a B- label that is not B0-Silent" + exit 1 +fi + +exit 0 diff --git a/scripts/github/runtime-version.rb b/scripts/github/runtime-version.rb new file mode 100644 index 0000000000..14663acaf3 --- /dev/null +++ b/scripts/github/runtime-version.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +# Gets the runtime version for a given runtime from the filesystem. +# Optionally accepts a path that is the root of the project which defaults to +# the current working directory +def get_runtime(runtime: nil, path: '.', runtime_dir: 'runtime') + File.open(path + "/#{runtime_dir}/#{runtime}/src/lib.rs") do |f| + f.find { |l| l =~ /spec_version/ }.match(/[0-9]+/)[0] + end +end diff --git a/scripts/scale_encode_genesis/index.js b/scripts/scale_encode_genesis/index.js new file mode 100644 index 0000000000..09df92ca96 --- /dev/null +++ b/scripts/scale_encode_genesis/index.js @@ -0,0 +1,41 @@ +const fs = require("fs"); +const { exit } = require("process"); +const {WsProvider, ApiPromise} = require("@polkadot/api"); +const util = require("@polkadot/util"); + +async function connect(port, types) { + const provider = new WsProvider("ws://127.0.0.1:" + port); + const api = await ApiPromise.create({ + provider, + types, + throwOnConnect: false, + }); + return api; +} + +if (!process.argv[2] || !process.argv[3]) { + console.log("usage: node generate_keys "); + exit(); +} + +const input = process.argv[2]; +const output = process.argv[3]; +fs.readFile(input, "utf8", (err, data) => { + if (err) { + console.log(`Error reading file from disk: ${err}`); + exit(1); + } + + const genesis = JSON.parse(data); + + connect(9944, {}).then(api => { + const setStorage = api.tx.system.setStorage(genesis); + const raw = setStorage.method.toU8a(); + const hex = util.u8aToHex(raw); + fs.writeFileSync(output, hex); + exit(0) + }).catch(e => { + console.error(e); + exit(1) + }); +}); diff --git a/scripts/scale_encode_genesis/package.json b/scripts/scale_encode_genesis/package.json new file mode 100644 index 0000000000..b39c31e0ee --- /dev/null +++ b/scripts/scale_encode_genesis/package.json @@ -0,0 +1,11 @@ +{ + "name": "y", + "version": "y", + "description": "create a scale encoded tx for the genesis values", + "main": "index.js", + "license": "MIT", + "dependencies": { + "@polkadot/api": "^6.5.2", + "@polkadot/util": "^7.6.1" + } +} diff --git a/scripts/scale_encode_genesis/yarn.lock b/scripts/scale_encode_genesis/yarn.lock new file mode 100644 index 0000000000..48698a06c8 --- /dev/null +++ b/scripts/scale_encode_genesis/yarn.lock @@ -0,0 +1,634 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/runtime@^7.15.3", "@babel/runtime@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.15.4.tgz#fd17d16bfdf878e6dd02d19753a39fa8a8d9c84a" + integrity sha512-99catp6bHCaxr4sJ/DbTGgHS4+Rs2RVd2g7iOap6SLGPDknRK9ztKNsE/Fg6QhSeh1FGE5f6gHGQmvvn3I3xhw== + dependencies: + regenerator-runtime "^0.13.4" + +"@polkadot/api-derive@6.5.2": + version "6.5.2" + resolved "https://registry.yarnpkg.com/@polkadot/api-derive/-/api-derive-6.5.2.tgz#1c14c4cda13bab958b55ce8973aed2a4388d400d" + integrity sha512-QD7xegHVLIrDxbuBiAF4wGzqXc/pXsfwTLpkVW1bT7Aa8pXWVTdahh4HCcgOq7c1i01QS2lQE21/4SSLG7KzUA== + dependencies: + "@babel/runtime" "^7.15.4" + "@polkadot/api" "6.5.2" + "@polkadot/rpc-core" "6.5.2" + "@polkadot/types" "6.5.2" + "@polkadot/util" "^7.6.1" + "@polkadot/util-crypto" "^7.6.1" + rxjs "^7.4.0" + +"@polkadot/api@6.5.2", "@polkadot/api@^6.5.2": + version "6.5.2" + resolved "https://registry.yarnpkg.com/@polkadot/api/-/api-6.5.2.tgz#40a2a2545cc3be19ce35b4c4b688c0a2055576bd" + integrity sha512-UNR8pynzPzS1GxpCoLh2a/iPf9lPYY03q0ZLZG/qYYFR+njeD7/4B5e+yEMHIDKS/+XAvM5zXDEbEtxHMiCR9A== + dependencies: + "@babel/runtime" "^7.15.4" + "@polkadot/api-derive" "6.5.2" + "@polkadot/keyring" "^7.6.1" + "@polkadot/rpc-core" "6.5.2" + "@polkadot/rpc-provider" "6.5.2" + "@polkadot/types" "6.5.2" + "@polkadot/types-known" "6.5.2" + "@polkadot/util" "^7.6.1" + "@polkadot/util-crypto" "^7.6.1" + eventemitter3 "^4.0.7" + rxjs "^7.4.0" + +"@polkadot/keyring@^7.6.1": + version "7.6.1" + resolved "https://registry.yarnpkg.com/@polkadot/keyring/-/keyring-7.6.1.tgz#a138e417cbbf85b3f0f66af66f5cd40735ba24a1" + integrity sha512-lpbTHAQqae++cvaNfuCjdz2xbNrk0ZSGCM8w08Br6NIz8NyrwR/qm1PfV75leoLq/Qx58+aj8v2qANEBOVz4vQ== + dependencies: + "@babel/runtime" "^7.15.4" + "@polkadot/util" "7.6.1" + "@polkadot/util-crypto" "7.6.1" + +"@polkadot/networks@7.6.1", "@polkadot/networks@^7.6.1": + version "7.6.1" + resolved "https://registry.yarnpkg.com/@polkadot/networks/-/networks-7.6.1.tgz#d7ca346a3c15b29c9286ccbc67b1438bf9c8130e" + integrity sha512-76RdEVy+G14P13oxSe3+VDwFdVYRNVAy7xi9ESJBRZFnQC/TIL2rOeg7Gq5+HP/mkgzG4gL5X30VdE+aKzokpA== + dependencies: + "@babel/runtime" "^7.15.4" + +"@polkadot/rpc-core@6.5.2": + version "6.5.2" + resolved "https://registry.yarnpkg.com/@polkadot/rpc-core/-/rpc-core-6.5.2.tgz#4dbdf39974284df9f0cc6897654c91b05db66482" + integrity sha512-ZZRUQqizqH2E4OZ61C1T78KnWm2OiewIZt0SomB5s7zc7ixwcvFltjlWdiuQspG2m4VMb46jFy3pVdkycgrMfg== + dependencies: + "@babel/runtime" "^7.15.4" + "@polkadot/rpc-provider" "6.5.2" + "@polkadot/types" "6.5.2" + "@polkadot/util" "^7.6.1" + rxjs "^7.4.0" + +"@polkadot/rpc-provider@6.5.2": + version "6.5.2" + resolved "https://registry.yarnpkg.com/@polkadot/rpc-provider/-/rpc-provider-6.5.2.tgz#359ba68ef5c171191bdd10867e99d3c7b7d71cc5" + integrity sha512-MFphpbI9zsYKGFb2mXkeOhWRiyDZxKYTyViVB5kE0YeMMl1DHR3YVfjR6t+K5H1A++iwh3xilkyZ8imcfTK/BQ== + dependencies: + "@babel/runtime" "^7.15.4" + "@polkadot/types" "6.5.2" + "@polkadot/util" "^7.6.1" + "@polkadot/util-crypto" "^7.6.1" + "@polkadot/x-fetch" "^7.6.1" + "@polkadot/x-global" "^7.6.1" + "@polkadot/x-ws" "^7.6.1" + eventemitter3 "^4.0.7" + +"@polkadot/types-known@6.5.2": + version "6.5.2" + resolved "https://registry.yarnpkg.com/@polkadot/types-known/-/types-known-6.5.2.tgz#a5b3afe7ddf9fc4a87f1b391d6d7058eb4e03ae0" + integrity sha512-5mFcsAJDL10pwTRI2ODNYvzeB1pQsSbYakI323BkA9iWxNSDYgHNU9prgEAnbO6VXP31HMX86ZDGhEm/XpGo4A== + dependencies: + "@babel/runtime" "^7.15.4" + "@polkadot/networks" "^7.6.1" + "@polkadot/types" "6.5.2" + "@polkadot/util" "^7.6.1" + +"@polkadot/types@6.5.2": + version "6.5.2" + resolved "https://registry.yarnpkg.com/@polkadot/types/-/types-6.5.2.tgz#76f5fb1b35ae20530554869b9a859811b4048b28" + integrity sha512-QDE5SxyW/Veq0IB8zT0RaBJTedmVkxhR8EykwslJiRuHSBz/HZjtEhcnA44c8fdKWKkbURklbX2vlWd7d2w4jQ== + dependencies: + "@babel/runtime" "^7.15.4" + "@polkadot/util" "^7.6.1" + "@polkadot/util-crypto" "^7.6.1" + rxjs "^7.4.0" + +"@polkadot/util-crypto@7.6.1", "@polkadot/util-crypto@^7.6.1": + version "7.6.1" + resolved "https://registry.yarnpkg.com/@polkadot/util-crypto/-/util-crypto-7.6.1.tgz#3e40270e9dce7885d92d0992aef9761feb57f2e2" + integrity sha512-5lLEfexkYOc73jitwC4K/Ll3JNA8Hdo2aU3GSOkDah8bBpm02djD7ypwfmuWRJw0UDyTgY67g0SXn4frPcQiag== + dependencies: + "@babel/runtime" "^7.15.4" + "@polkadot/networks" "7.6.1" + "@polkadot/util" "7.6.1" + "@polkadot/wasm-crypto" "^4.2.1" + "@polkadot/x-randomvalues" "7.6.1" + base-x "^3.0.9" + base64-js "^1.5.1" + blakejs "^1.1.1" + bn.js "^4.12.0" + create-hash "^1.2.0" + ed2curve "^0.3.0" + elliptic "^6.5.4" + hash.js "^1.1.7" + js-sha3 "^0.8.0" + scryptsy "^2.1.0" + tweetnacl "^1.0.3" + xxhashjs "^0.2.2" + +"@polkadot/util@7.6.1", "@polkadot/util@^7.6.1": + version "7.6.1" + resolved "https://registry.yarnpkg.com/@polkadot/util/-/util-7.6.1.tgz#e6988124728fdf053929022827216241dd50a6fa" + integrity sha512-96UgzMOxwwsndGHN4aoyPYVRXpHcVpYb4zngFH2O9ma0YxrG2HhhqqoJ5pS0OUlhvcQkVz6T6t+heGFnTkvQxw== + dependencies: + "@babel/runtime" "^7.15.4" + "@polkadot/x-textdecoder" "7.6.1" + "@polkadot/x-textencoder" "7.6.1" + "@types/bn.js" "^4.11.6" + bn.js "^4.12.0" + camelcase "^6.2.0" + ip-regex "^4.3.0" + +"@polkadot/wasm-crypto-asmjs@^4.2.1": + version "4.2.1" + resolved "https://registry.yarnpkg.com/@polkadot/wasm-crypto-asmjs/-/wasm-crypto-asmjs-4.2.1.tgz#6b7eae1c011709f8042dfd30872a5fc5e9e021c0" + integrity sha512-ON9EBpTNDCI3QRUmuQJIegYoAcwvxDaNNA7uwKTaEEStu8LjCIbQxbt4WbOBYWI0PoUpl4iIluXdT3XZ3V3jXA== + dependencies: + "@babel/runtime" "^7.15.3" + +"@polkadot/wasm-crypto-wasm@^4.2.1": + version "4.2.1" + resolved "https://registry.yarnpkg.com/@polkadot/wasm-crypto-wasm/-/wasm-crypto-wasm-4.2.1.tgz#2a86f9b405e7195c3f523798c6ce4afffd19737e" + integrity sha512-Rs2CKiR4D+2hKzmKBfPNYxcd2E8NfLWia0av4fgicjT9YsWIWOGQUi9AtSOfazPOR9FrjxKJy+chQxAkcfKMnQ== + dependencies: + "@babel/runtime" "^7.15.3" + +"@polkadot/wasm-crypto@^4.2.1": + version "4.2.1" + resolved "https://registry.yarnpkg.com/@polkadot/wasm-crypto/-/wasm-crypto-4.2.1.tgz#4d09402f5ac71a90962fb58cbe4b1707772a4fb6" + integrity sha512-C/A/QnemOilRTLnM0LfhPY2N/x3ZFd1ihm9sXYyuh98CxtekSVYI9h4IJ5Jrgz5imSUHgvt9oJLqJ5GbWQV/Zg== + dependencies: + "@babel/runtime" "^7.15.3" + "@polkadot/wasm-crypto-asmjs" "^4.2.1" + "@polkadot/wasm-crypto-wasm" "^4.2.1" + +"@polkadot/x-fetch@^7.6.1": + version "7.6.1" + resolved "https://registry.yarnpkg.com/@polkadot/x-fetch/-/x-fetch-7.6.1.tgz#fda1a89bbb584217f96c2d3c3a3ce0f10a454436" + integrity sha512-CdjCg7BGhKfKNntUiK9vFOoum44o86TInPpqNumLGWAZmqI+kU0DCUDtqcw7uFOdZL1j/3GHdXigJ6LL1TnNcg== + dependencies: + "@babel/runtime" "^7.15.4" + "@polkadot/x-global" "7.6.1" + "@types/node-fetch" "^2.5.12" + node-fetch "^2.6.5" + +"@polkadot/x-global@7.6.1", "@polkadot/x-global@^7.6.1": + version "7.6.1" + resolved "https://registry.yarnpkg.com/@polkadot/x-global/-/x-global-7.6.1.tgz#f43a61d40bfaf2f43f9a4ef39e01a24546768394" + integrity sha512-jKPNFHiC0yIc6TfqZtopaqsW3pDun1uh9lp0kcDkfOYozwwN1NVXWLClDBa2C5UiKU/jxA3biYiNZUyZpbV13g== + dependencies: + "@babel/runtime" "^7.15.4" + +"@polkadot/x-randomvalues@7.6.1": + version "7.6.1" + resolved "https://registry.yarnpkg.com/@polkadot/x-randomvalues/-/x-randomvalues-7.6.1.tgz#0cd143cf976e36f5c9fcf53ba41fd5fffca95c44" + integrity sha512-hfSMBeMZTrnuejv/oXp3tMZARTOGyQZ3G0GW44dV2fR2L1+tlLj9VuXgVGgupNBq7AC6eSfE3XhJwCGyH5FhmQ== + dependencies: + "@babel/runtime" "^7.15.4" + "@polkadot/x-global" "7.6.1" + +"@polkadot/x-textdecoder@7.6.1": + version "7.6.1" + resolved "https://registry.yarnpkg.com/@polkadot/x-textdecoder/-/x-textdecoder-7.6.1.tgz#7e80b512f1ddfd01f243dbbe8afc9dab7d0c6c85" + integrity sha512-sJtQMMw+jO3CwpOf0t1hrVl3xMw1BOLs/Xjd0v/yhiTAJ1rr6dqvhcnOHkU3a7udqo7G9dXDrnGi1q3efifXPw== + dependencies: + "@babel/runtime" "^7.15.4" + "@polkadot/x-global" "7.6.1" + +"@polkadot/x-textencoder@7.6.1": + version "7.6.1" + resolved "https://registry.yarnpkg.com/@polkadot/x-textencoder/-/x-textencoder-7.6.1.tgz#2a2fb4baa13889fbc53b86ce9003de748f0df2aa" + integrity sha512-iqOGwXJIzc8rWYLPTYcO09LwA2q4fqwJhLsLCd+p13Z0yDSUvwgq785/2WEQfhSFbMd8HM6udedqrQTpnpIujg== + dependencies: + "@babel/runtime" "^7.15.4" + "@polkadot/x-global" "7.6.1" + +"@polkadot/x-ws@^7.6.1": + version "7.6.1" + resolved "https://registry.yarnpkg.com/@polkadot/x-ws/-/x-ws-7.6.1.tgz#60c86cfb43935b38a6512f3e7bab362ffe6bec1f" + integrity sha512-nP8vHlL17SIuVinphuVbj2o3mfRWUTJqlhAYlA5RjO/sZ9TwYMvGTvL/1bOAfWdp/l451WLEWJtzSipzrVGBsg== + dependencies: + "@babel/runtime" "^7.15.4" + "@polkadot/x-global" "7.6.1" + "@types/websocket" "^1.0.4" + websocket "^1.0.34" + +"@types/bn.js@^4.11.6": + version "4.11.6" + resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-4.11.6.tgz#c306c70d9358aaea33cd4eda092a742b9505967c" + integrity sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg== + dependencies: + "@types/node" "*" + +"@types/node-fetch@^2.5.12": + version "2.5.12" + resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.12.tgz#8a6f779b1d4e60b7a57fb6fd48d84fb545b9cc66" + integrity sha512-MKgC4dlq4kKNa/mYrwpKfzQMB5X3ee5U6fSprkKpToBqBmX4nFZL9cW5jl6sWn+xpRJ7ypWh2yyqqr8UUCstSw== + dependencies: + "@types/node" "*" + form-data "^3.0.0" + +"@types/node@*": + version "16.11.6" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae" + integrity sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w== + +"@types/websocket@^1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@types/websocket/-/websocket-1.0.4.tgz#1dc497280d8049a5450854dd698ee7e6ea9e60b8" + integrity sha512-qn1LkcFEKK8RPp459jkjzsfpbsx36BBt3oC3pITYtkoBw/aVX+EZFa5j3ThCRTNpLFvIMr5dSTD4RaMdilIOpA== + dependencies: + "@types/node" "*" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= + +base-x@^3.0.9: + version "3.0.9" + resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.9.tgz#6349aaabb58526332de9f60995e548a53fe21320" + integrity sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ== + dependencies: + safe-buffer "^5.0.1" + +base64-js@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +blakejs@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.1.1.tgz#bf313053978b2cd4c444a48795710be05c785702" + integrity sha512-bLG6PHOCZJKNshTjGRBvET0vTciwQE6zFKOKKXPDJfwFBd4Ac0yBfPZqcGvGJap50l7ktvlpFqc2jGVaUgbJgg== + +bn.js@^4.11.9, bn.js@^4.12.0: + version "4.12.0" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" + integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== + +brorand@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= + +bufferutil@^4.0.1: + version "4.0.5" + resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.5.tgz#da9ea8166911cc276bf677b8aed2d02d31f59028" + integrity sha512-HTm14iMQKK2FjFLRTM5lAVcyaUzOnqbPtesFIvREgXpJHdQm8bWS+GkQgIkfaBYRHuCnea7w8UVNfwiAQhlr9A== + dependencies: + node-gyp-build "^4.3.0" + +camelcase@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809" + integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg== + +cipher-base@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +create-hash@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + +cuint@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/cuint/-/cuint-0.2.2.tgz#408086d409550c2631155619e9fa7bcadc3b991b" + integrity sha1-QICG1AlVDCYxFVYZ6fp7ytw7mRs= + +d@1, d@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a" + integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA== + dependencies: + es5-ext "^0.10.50" + type "^1.0.1" + +debug@^2.2.0: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + +ed2curve@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/ed2curve/-/ed2curve-0.3.0.tgz#322b575152a45305429d546b071823a93129a05d" + integrity sha512-8w2fmmq3hv9rCrcI7g9hms2pMunQr1JINfcjwR9tAyZqhtyaMN991lF/ZfHfr5tzZQ8c7y7aBgZbjfbd0fjFwQ== + dependencies: + tweetnacl "1.x.x" + +elliptic@^6.5.4: + version "6.5.4" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" + integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== + dependencies: + bn.js "^4.11.9" + brorand "^1.1.0" + hash.js "^1.0.0" + hmac-drbg "^1.0.1" + inherits "^2.0.4" + minimalistic-assert "^1.0.1" + minimalistic-crypto-utils "^1.0.1" + +es5-ext@^0.10.35, es5-ext@^0.10.50: + version "0.10.53" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.53.tgz#93c5a3acfdbef275220ad72644ad02ee18368de1" + integrity sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q== + dependencies: + es6-iterator "~2.0.3" + es6-symbol "~3.1.3" + next-tick "~1.0.0" + +es6-iterator@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" + integrity sha1-p96IkUGgWpSwhUQDstCg+/qY87c= + dependencies: + d "1" + es5-ext "^0.10.35" + es6-symbol "^3.1.1" + +es6-symbol@^3.1.1, es6-symbol@~3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18" + integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA== + dependencies: + d "^1.0.1" + ext "^1.1.2" + +eventemitter3@^4.0.7: + version "4.0.7" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== + +ext@^1.1.2: + version "1.6.0" + resolved "https://registry.yarnpkg.com/ext/-/ext-1.6.0.tgz#3871d50641e874cc172e2b53f919842d19db4c52" + integrity sha512-sdBImtzkq2HpkdRLtlLWDa6w4DX22ijZLKx8BMPUuKe1c5lbN6xwQDQCxSfxBQnHZ13ls/FH0MQZx/q/gr6FQg== + dependencies: + type "^2.5.0" + +form-data@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" + integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +hash-base@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" + integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== + dependencies: + inherits "^2.0.4" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" + +hash.js@^1.0.0, hash.js@^1.0.3, hash.js@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + +hmac-drbg@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +ip-regex@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-4.3.0.tgz#687275ab0f57fa76978ff8f4dddc8a23d5990db5" + integrity sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q== + +is-typedarray@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= + +js-sha3@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" + integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== + +md5.js@^1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" + integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +mime-db@1.50.0: + version "1.50.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.50.0.tgz#abd4ac94e98d3c0e185016c67ab45d5fde40c11f" + integrity sha512-9tMZCDlYHqeERXEHO9f/hKfNXhre5dK2eE/krIvUjZbS2KPcqGDfNShIWS1uW9XOTKQKqK6qbeOci18rbfW77A== + +mime-types@^2.1.12: + version "2.1.33" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.33.tgz#1fa12a904472fafd068e48d9e8401f74d3f70edb" + integrity sha512-plLElXp7pRDd0bNZHw+nMd52vRYjLwQjygaNg7ddJ2uJtTlmnTCjWuPKxVu6//AdaRuME84SvLW91sIkBqGT0g== + dependencies: + mime-db "1.50.0" + +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +next-tick@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" + integrity sha1-yobR/ogoFpsBICCOPchCS524NCw= + +node-fetch@^2.6.5: + version "2.6.5" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.5.tgz#42735537d7f080a7e5f78b6c549b7146be1742fd" + integrity sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ== + dependencies: + whatwg-url "^5.0.0" + +node-gyp-build@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.3.0.tgz#9f256b03e5826150be39c764bf51e993946d71a3" + integrity sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q== + +readable-stream@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +regenerator-runtime@^0.13.4: + version "0.13.9" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" + integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== + +ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +rxjs@^7.4.0: + version "7.4.0" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.4.0.tgz#a12a44d7eebf016f5ff2441b87f28c9a51cebc68" + integrity sha512-7SQDi7xeTMCJpqViXh8gL/lebcwlp3d831F05+9B44A4B0WfsEwUQHR64gsH1kvJ+Ep/J9K2+n1hVl1CsGN23w== + dependencies: + tslib "~2.1.0" + +safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +scryptsy@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/scryptsy/-/scryptsy-2.1.0.tgz#8d1e8d0c025b58fdd25b6fa9a0dc905ee8faa790" + integrity sha512-1CdSqHQowJBnMAFyPEBRfqag/YP9OF394FV+4YREIJX4ljD7OxvQRDayyoyyCk+senRjSkP6VnUNQmVQqB6g7w== + +sha.js@^2.4.0: + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= + +tslib@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a" + integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A== + +tweetnacl@1.x.x, tweetnacl@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596" + integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw== + +type@^1.0.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0" + integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg== + +type@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/type/-/type-2.5.0.tgz#0a2e78c2e77907b252abe5f298c1b01c63f0db3d" + integrity sha512-180WMDQaIMm3+7hGXWf12GtdniDEy7nYcyFMKJn/eZz/6tSLXrUN9V0wKSbMjej0I1WHWbpREDEKHtqPQa9NNw== + +typedarray-to-buffer@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" + integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== + dependencies: + is-typedarray "^1.0.0" + +utf-8-validate@^5.0.2: + version "5.0.7" + resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-5.0.7.tgz#c15a19a6af1f7ad9ec7ddc425747ca28c3644922" + integrity sha512-vLt1O5Pp+flcArHGIyKEQq883nBt8nN8tVBcoL0qUXj2XT1n7p70yGIq2VK98I5FdZ1YHc0wk/koOnHjnXWk1Q== + dependencies: + node-gyp-build "^4.3.0" + +util-deprecate@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= + +websocket@^1.0.34: + version "1.0.34" + resolved "https://registry.yarnpkg.com/websocket/-/websocket-1.0.34.tgz#2bdc2602c08bf2c82253b730655c0ef7dcab3111" + integrity sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ== + dependencies: + bufferutil "^4.0.1" + debug "^2.2.0" + es5-ext "^0.10.50" + typedarray-to-buffer "^3.1.5" + utf-8-validate "^5.0.2" + yaeti "^0.0.6" + +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0= + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + +xxhashjs@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/xxhashjs/-/xxhashjs-0.2.2.tgz#8a6251567621a1c46a5ae204da0249c7f8caa9d8" + integrity sha512-AkTuIuVTET12tpsVIQo+ZU6f/qDmKuRUcjaqR+OIvm+aCBsZ95i7UVY5WJ9TMsSaZ0DA2WxoZ4acu0sPH+OKAw== + dependencies: + cuint "^0.2.2" + +yaeti@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/yaeti/-/yaeti-0.0.6.tgz#f26f484d72684cf42bedfb76970aa1608fbf9577" + integrity sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc= diff --git a/test/client/Cargo.toml b/test/client/Cargo.toml index 2ae58f6775..198c551fb2 100644 --- a/test/client/Cargo.toml +++ b/test/client/Cargo.toml @@ -2,7 +2,7 @@ name = "cumulus-test-client" version = "0.1.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" [dependencies] sc-service = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/test/client/src/lib.rs b/test/client/src/lib.rs index 3ae25321d0..adbd2e363e 100644 --- a/test/client/src/lib.rs +++ b/test/client/src/lib.rs @@ -22,7 +22,7 @@ use runtime::{ Balance, Block, BlockHashCount, Call, GenesisConfig, Runtime, Signature, SignedExtra, SignedPayload, UncheckedExtrinsic, VERSION, }; -use sc_executor::{sp_wasm_interface::HostFunctions, WasmExecutionMethod, WasmExecutor}; +use sc_executor::{WasmExecutionMethod, WasmExecutor}; use sc_executor_common::runtime_blob::RuntimeBlob; use sc_service::client; use sp_blockchain::HeaderBackend; @@ -122,7 +122,7 @@ fn genesis_config() -> GenesisConfig { pub fn generate_extrinsic( client: &Client, origin: sp_keyring::AccountKeyring, - function: Call, + function: impl Into, ) -> UncheckedExtrinsic { let current_block_hash = client.info().best_hash; let current_block = client.info().best_number.saturated_into(); @@ -132,6 +132,7 @@ pub fn generate_extrinsic( BlockHashCount::get().checked_next_power_of_two().map(|c| c / 2).unwrap_or(2) as u64; let tip = 0; let extra: SignedExtra = ( + frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckGenesis::::new(), frame_system::CheckEra::::from(Era::mortal(period, current_block)), @@ -139,10 +140,13 @@ pub fn generate_extrinsic( frame_system::CheckWeight::::new(), pallet_transaction_payment::ChargeTransactionPayment::::from(tip), ); + + let function = function.into(); + let raw_payload = SignedPayload::from_raw( function.clone(), extra.clone(), - (VERSION.spec_version, genesis_block, current_block_hash, (), (), ()), + ((), VERSION.spec_version, genesis_block, current_block_hash, (), (), ()), ); let signature = raw_payload.using_encoded(|e| origin.sign(e)); @@ -175,12 +179,12 @@ pub fn validate_block( let mut ext = TestExternalities::default(); let mut ext_ext = ext.ext(); - let executor = WasmExecutor::new( + let executor = WasmExecutor::::new( WasmExecutionMethod::Interpreted, Some(1024), - sp_io::SubstrateHostFunctions::host_functions(), 1, None, + 2, ); executor diff --git a/test/relay-sproof-builder/Cargo.toml b/test/relay-sproof-builder/Cargo.toml index a951fddf1c..4abd2dfd4b 100644 --- a/test/relay-sproof-builder/Cargo.toml +++ b/test/relay-sproof-builder/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "cumulus-test-relay-sproof-builder" -version = '0.1.0' +version = "0.1.0" authors = ["Parity Technologies "] -edition = '2018' +edition = "2021" [dependencies] # Other dependencies diff --git a/test/relay-sproof-builder/src/lib.rs b/test/relay-sproof-builder/src/lib.rs index a3ad558c0f..8345e43471 100644 --- a/test/relay-sproof-builder/src/lib.rs +++ b/test/relay-sproof-builder/src/lib.rs @@ -56,7 +56,7 @@ impl Default for RelayStateSproofBuilder { max_upward_message_size: 256, max_upward_message_num_per_candidate: 5, hrmp_max_message_num_per_candidate: 5, - validation_upgrade_frequency: 6, + validation_upgrade_cooldown: 6, validation_upgrade_delay: 6, }, dmq_mqc_head: None, @@ -118,15 +118,16 @@ impl RelayStateSproofBuilder { self, ) -> (polkadot_primitives::v1::Hash, sp_state_machine::StorageProof) { let (db, root) = MemoryDB::>::default_with_root(); + let state_version = Default::default(); // for test using default. let mut backend = sp_state_machine::TrieBackend::new(db, root); - let mut relevant_keys = vec![]; + let mut relevant_keys = Vec::new(); { use codec::Encode as _; let mut insert = |key: Vec, value: Vec| { relevant_keys.push(key.clone()); - backend.insert(vec![(None, vec![(key, Some(value))])]); + backend.insert(vec![(None, vec![(key, Some(value))])], state_version); }; insert(relay_chain::well_known_keys::ACTIVE_CONFIG.to_vec(), self.host_config.encode()); diff --git a/test/relay-validation-worker-provider/Cargo.toml b/test/relay-validation-worker-provider/Cargo.toml index 9946a29b70..750b863bae 100644 --- a/test/relay-validation-worker-provider/Cargo.toml +++ b/test/relay-validation-worker-provider/Cargo.toml @@ -2,7 +2,7 @@ name = "cumulus-test-relay-validation-worker-provider" version = "0.1.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" build = "build.rs" [dependencies] diff --git a/test/relay-validation-worker-provider/build.rs b/test/relay-validation-worker-provider/build.rs index cb0a71681c..1b7a5dd098 100644 --- a/test/relay-validation-worker-provider/build.rs +++ b/test/relay-validation-worker-provider/build.rs @@ -65,7 +65,7 @@ fn create_project(out_dir: &Path) -> PathBuf { name = "{project_name}" version = "0.1.0" authors = ["Parity Technologies "] - edition = "2018" + edition = "2021" [dependencies] cumulus-test-relay-validation-worker-provider = {{ path = "{provider_path}" }} diff --git a/test/runtime-upgrade/build.rs b/test/runtime-upgrade/build.rs deleted file mode 120000 index f0e55a8c43..0000000000 --- a/test/runtime-upgrade/build.rs +++ /dev/null @@ -1 +0,0 @@ -../runtime/build.rs \ No newline at end of file diff --git a/test/runtime-upgrade/src b/test/runtime-upgrade/src deleted file mode 120000 index b374eea6a3..0000000000 --- a/test/runtime-upgrade/src +++ /dev/null @@ -1 +0,0 @@ -../runtime/src \ No newline at end of file diff --git a/test/runtime/Cargo.toml b/test/runtime/Cargo.toml index 9b6cadb634..25c1b546c7 100644 --- a/test/runtime/Cargo.toml +++ b/test/runtime/Cargo.toml @@ -2,19 +2,19 @@ name = "cumulus-test-runtime" version = "0.1.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" [dependencies] codec = { package = "parity-scale-codec", version = "2.3.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.101", optional = true, features = ["derive"] } +serde = { version = "1.0.132", optional = true, features = ["derive"] } # Substrate dependencies frame-executive = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } frame-system = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } +frame-system-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } pallet-balances = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } -pallet-randomness-collective-flip = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } pallet-sudo = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } pallet-timestamp = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } @@ -49,8 +49,8 @@ std = [ "frame-executive/std", "frame-support/std", "frame-system/std", + "frame-system-rpc-runtime-api/std", "pallet-balances/std", - "pallet-randomness-collective-flip/std", "pallet-sudo/std", "pallet-timestamp/std", "pallet-transaction-payment/std", @@ -67,4 +67,4 @@ std = [ "sp-transaction-pool/std", "sp-version/std", ] -upgrade = [] +increment-spec-version = [] diff --git a/test/runtime/build.rs b/test/runtime/build.rs index fe1a2ea911..0b9594e612 100644 --- a/test/runtime/build.rs +++ b/test/runtime/build.rs @@ -21,5 +21,12 @@ fn main() { .with_current_project() .export_heap_base() .import_memory() - .build() + .build(); + + WasmBuilder::new() + .with_current_project() + .enable_feature("increment-spec-version") + .import_memory() + .set_file_name("wasm_binary_spec_version_incremented.rs") + .build(); } diff --git a/test/runtime/src/lib.rs b/test/runtime/src/lib.rs index 64fef7a031..728a054a3e 100644 --- a/test/runtime/src/lib.rs +++ b/test/runtime/src/lib.rs @@ -22,6 +22,14 @@ #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); +pub mod wasm_spec_version_incremented { + #[cfg(feature = "std")] + include!(concat!(env!("OUT_DIR"), "/wasm_binary_spec_version_incremented.rs")); +} + +mod test_pallet; + +use frame_support::traits::OnRuntimeUpgrade; use sp_api::{decl_runtime_apis, impl_runtime_apis}; use sp_core::OpaqueMetadata; use sp_runtime::{ @@ -52,6 +60,7 @@ pub use pallet_timestamp::Call as TimestampCall; #[cfg(any(feature = "std", test))] pub use sp_runtime::BuildStorage; pub use sp_runtime::{Perbill, Permill}; +pub use test_pallet::Call as TestPalletCall; pub type SessionHandlers = (); @@ -59,9 +68,13 @@ impl_opaque_keys! { pub struct SessionKeys {} } +/// Some key that we set in genesis and only read in [`TestRuntimeUpgrade`] to ensure that +/// [`OnRuntimeUpgrade`] works as expected. +pub const TEST_RUNTIME_UPGRADE_KEY: &[u8] = b"+test_runtime_upgrade_key+"; + // The only difference between the two declarations below is the `spec_version`. With the -// `upgrade` feature enabled `spec_version` should be greater than the one of without the -// `upgrade` feature. +// `increment-spec-version` feature enabled `spec_version` should be greater than the one of without the +// `increment-spec-version` feature. // // The duplication here is unfortunate necessity. // @@ -70,30 +83,32 @@ impl_opaque_keys! { // details. Since macro kicks in early, it operates on AST. Thus you cannot use constants. // Macros are expanded top to bottom, meaning we also cannot use `cfg` here. -#[cfg(feature = "upgrade")] +#[cfg(not(feature = "increment-spec-version"))] #[sp_version::runtime_version] pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("cumulus-test-parachain"), impl_name: create_runtime_str!("cumulus-test-parachain"), authoring_version: 1, // Read the note above. - spec_version: 4, + spec_version: 1, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, + state_version: 1, }; -#[cfg(not(feature = "upgrade"))] +#[cfg(feature = "increment-spec-version")] #[sp_version::runtime_version] pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("cumulus-test-parachain"), impl_name: create_runtime_str!("cumulus-test-parachain"), authoring_version: 1, // Read the note above. - spec_version: 3, + spec_version: 2, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, + state_version: 1, }; pub const MILLISECS_PER_BLOCK: u64 = 12000; @@ -187,6 +202,7 @@ impl frame_system::Config for Runtime { type BlockLength = RuntimeBlockLength; type SS58Prefix = SS58Prefix; type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { @@ -235,8 +251,6 @@ impl pallet_transaction_payment::Config for Runtime { type OperationalFeeMultiplier = OperationalFeeMultiplier; } -impl pallet_randomness_collective_flip::Config for Runtime {} - impl pallet_sudo::Config for Runtime { type Call = Call; type Event = Event; @@ -257,21 +271,21 @@ parameter_types! { pub storage ParachainId: cumulus_primitives_core::ParaId = 100.into(); } +impl test_pallet::Config for Runtime {} + construct_runtime! { pub enum Runtime where Block = Block, NodeBlock = NodeBlock, UncheckedExtrinsic = UncheckedExtrinsic, { - System: frame_system::{Pallet, Call, Storage, Config, Event}, - ParachainSystem: cumulus_pallet_parachain_system::{ - Pallet, Call, Config, Storage, Inherent, Event, ValidateUnsigned, - }, - Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent}, - Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - Sudo: pallet_sudo::{Pallet, Call, Storage, Config, Event}, - RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Pallet, Storage}, - TransactionPayment: pallet_transaction_payment::{Pallet, Storage}, + System: frame_system, + ParachainSystem: cumulus_pallet_parachain_system, + Timestamp: pallet_timestamp, + Balances: pallet_balances, + Sudo: pallet_sudo, + TransactionPayment: pallet_transaction_payment, + TestPallet: test_pallet, } } @@ -303,6 +317,7 @@ pub type SignedBlock = generic::SignedBlock; pub type BlockId = generic::BlockId; /// The SignedExtension to the basic transaction logic. pub type SignedExtra = ( + frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckGenesis, frame_system::CheckEra, @@ -320,11 +335,22 @@ pub type Executive = frame_executive::Executive< Block, frame_system::ChainContext, Runtime, - AllPallets, + AllPalletsWithSystem, + TestOnRuntimeUpgrade, >; /// The payload being signed in transactions. pub type SignedPayload = generic::SignedPayload; +pub struct TestOnRuntimeUpgrade; + +impl OnRuntimeUpgrade for TestOnRuntimeUpgrade { + fn on_runtime_upgrade() -> frame_support::weights::Weight { + assert_eq!(sp_io::storage::get(TEST_RUNTIME_UPGRADE_KEY), Some(vec![1, 2, 3, 4])); + + 1 + } +} + decl_runtime_apis! { pub trait GetLastTimestamp { /// Returns the last timestamp of a runtime. @@ -353,6 +379,12 @@ impl_runtime_apis! { } } + impl frame_system_rpc_runtime_api::AccountNonceApi for Runtime { + fn account_nonce(account: AccountId) -> Index { + System::account_nonce(account) + } + } + impl sp_block_builder::BlockBuilder for Runtime { fn apply_extrinsic( extrinsic: ::Extrinsic, diff --git a/test/runtime/src/test_pallet.rs b/test/runtime/src/test_pallet.rs new file mode 100644 index 0000000000..facb929dc9 --- /dev/null +++ b/test/runtime/src/test_pallet.rs @@ -0,0 +1,49 @@ +// Copyright 2021 Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . + +/// A special pallet that exposes dispatchables that are only useful for testing. +pub use pallet::*; + +#[frame_support::pallet] +pub mod pallet { + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config + cumulus_pallet_parachain_system::Config {} + + #[pallet::hooks] + impl Hooks> for Pallet {} + + #[pallet::call] + impl Pallet { + /// A test dispatchable for setting a custom head data in `validate_block`. + #[pallet::weight(0)] + pub fn set_custom_validation_head_data( + _: OriginFor, + custom_header: sp_std::vec::Vec, + ) -> DispatchResult { + cumulus_pallet_parachain_system::Pallet::::set_custom_validation_head_data( + custom_header, + ); + Ok(()) + } + } +} diff --git a/test/service/Cargo.toml b/test/service/Cargo.toml index f0cfe177c9..0253713884 100644 --- a/test/service/Cargo.toml +++ b/test/service/Cargo.toml @@ -2,21 +2,23 @@ name = "cumulus-test-service" version = "0.1.0" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" [dependencies] codec = { package = "parity-scale-codec", version = "2.3.0" } rand = "0.7.3" -serde = { version = "1.0.101", features = ["derive"] } +serde = { version = "1.0.132", features = ["derive"] } async-trait = "0.1.42" tokio = { version = "1.10", features = ["macros"] } # Substrate frame-system = { git = "https://github.com/paritytech/substrate", branch = "master" } pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "master" } +frame-system-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "master" } sc-basic-authorship = { git = "https://github.com/paritytech/substrate", branch = "master" } sc-chain-spec = { git = "https://github.com/paritytech/substrate", branch = "master" } sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-transaction-pool-api = { git = "https://github.com/paritytech/substrate", branch = "master" } sc-consensus = { git = "https://github.com/paritytech/substrate", branch = "master" } sc-executor = { git = "https://github.com/paritytech/substrate", branch = "master" } sc-network = { git = "https://github.com/paritytech/substrate", branch = "master" } @@ -27,11 +29,13 @@ sc-transaction-pool = { git = "https://github.com/paritytech/substrate", branch sp-arithmetic = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-io = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } sp-state-machine = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-timestamp = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-tracing = { git = "https://github.com/paritytech/substrate", branch = "master" } substrate-test-client = { git = "https://github.com/paritytech/substrate", branch = "master" } # Polkadot @@ -48,6 +52,11 @@ cumulus-primitives-core = { path = "../../primitives/core" } cumulus-primitives-parachain-inherent = { path = "../../primitives/parachain-inherent" } cumulus-test-runtime = { path = "../runtime" } cumulus-test-relay-validation-worker-provider = { path = "../relay-validation-worker-provider" } +cumulus-relay-chain-local = { path = "../../client/relay-chain-local" } + +criterion = { version = "0.3.5", features = [ "async_tokio" ] } + +parking_lot = "0.11.1" # RPC related dependencies jsonrpc-core = "18.0.0" @@ -61,8 +70,7 @@ polkadot-test-service = { git = "https://github.com/paritytech/polkadot", branch # Substrate dependencies sc-cli = { git = "https://github.com/paritytech/substrate", branch = "master" } substrate-test-utils = { git = "https://github.com/paritytech/substrate", branch = "master" } -sp-maybe-compressed-blob = { git = "https://github.com/paritytech/substrate", branch = "master" } -sp-version = { git = "https://github.com/paritytech/substrate", branch = "master" } -# Cumulus -cumulus-test-runtime-upgrade = { path = "../runtime-upgrade" } +[[bench]] +name = "transaction_throughput" +harness = false diff --git a/test/service/benches/transaction_throughput.rs b/test/service/benches/transaction_throughput.rs new file mode 100644 index 0000000000..0ad9b3a3f1 --- /dev/null +++ b/test/service/benches/transaction_throughput.rs @@ -0,0 +1,246 @@ +// This file is part of Cumulus. + +// Copyright (C) 2021 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 criterion::{criterion_group, criterion_main, BatchSize, Criterion, Throughput}; +use cumulus_test_runtime::{AccountId, BalancesCall, ExistentialDeposit, SudoCall}; +use futures::{future, StreamExt}; +use sc_transaction_pool_api::{TransactionPool as _, TransactionSource, TransactionStatus}; +use sp_core::{crypto::Pair, sr25519}; +use sp_runtime::{generic::BlockId, OpaqueExtrinsic}; + +use cumulus_primitives_core::ParaId; +use cumulus_test_service::{ + construct_extrinsic, fetch_nonce, initial_head_data, Client, Keyring::*, TransactionPool, +}; + +fn create_accounts(num: usize) -> Vec { + (0..num) + .map(|i| { + Pair::from_string(&format!("{}/{}", Alice.to_seed(), i), None) + .expect("Creates account pair") + }) + .collect() +} + +/// Create the extrinsics that will initialize the accounts from the sudo account (Alice). +/// +/// `start_nonce` is the current nonce of Alice. +fn create_account_extrinsics(client: &Client, accounts: &[sr25519::Pair]) -> Vec { + let start_nonce = fetch_nonce(client, Alice.public()); + + accounts + .iter() + .enumerate() + .map(|(i, a)| { + vec![ + // Reset the nonce by removing any funds + construct_extrinsic( + client, + SudoCall::sudo { + call: Box::new( + BalancesCall::set_balance { + who: AccountId::from(a.public()).into(), + new_free: 0, + new_reserved: 0, + } + .into(), + ), + }, + Alice.pair(), + Some(start_nonce + (i as u32) * 2), + ), + // Give back funds + construct_extrinsic( + client, + SudoCall::sudo { + call: Box::new( + BalancesCall::set_balance { + who: AccountId::from(a.public()).into(), + new_free: 1_000_000 * ExistentialDeposit::get(), + new_reserved: 0, + } + .into(), + ), + }, + Alice.pair(), + Some(start_nonce + (i as u32) * 2 + 1), + ), + ] + }) + .flatten() + .map(OpaqueExtrinsic::from) + .collect() +} + +fn create_benchmark_extrinsics( + client: &Client, + accounts: &[sr25519::Pair], + extrinsics_per_account: usize, +) -> Vec { + accounts + .iter() + .map(|account| { + (0..extrinsics_per_account).map(move |nonce| { + construct_extrinsic( + client, + BalancesCall::transfer { + dest: Bob.to_account_id().into(), + value: 1 * ExistentialDeposit::get(), + }, + account.clone(), + Some(nonce as u32), + ) + }) + }) + .flatten() + .map(OpaqueExtrinsic::from) + .collect() +} + +async fn submit_tx_and_wait_for_inclusion( + tx_pool: &TransactionPool, + tx: OpaqueExtrinsic, + client: &Client, + wait_for_finalized: bool, +) { + let best_hash = client.chain_info().best_hash; + + let mut watch = tx_pool + .submit_and_watch(&BlockId::Hash(best_hash), TransactionSource::External, tx.clone()) + .await + .expect("Submits tx to pool") + .fuse(); + + loop { + match watch.select_next_some().await { + TransactionStatus::Finalized(_) => break, + TransactionStatus::InBlock(_) if !wait_for_finalized => break, + _ => {}, + } + } +} + +fn transaction_throughput_benchmarks(c: &mut Criterion) { + sp_tracing::try_init_simple(); + let mut builder = sc_cli::LoggerBuilder::new(""); + builder.with_colors(false); + let _ = builder.init(); + + let para_id = ParaId::from(100); + let runtime = tokio::runtime::Runtime::new().expect("Creates tokio runtime"); + let tokio_handle = runtime.handle(); + + // Start alice + let alice = cumulus_test_service::run_relay_chain_validator_node( + tokio_handle.clone(), + Alice, + || {}, + vec![], + ); + + // Start bob + let bob = cumulus_test_service::run_relay_chain_validator_node( + tokio_handle.clone(), + Bob, + || {}, + vec![alice.addr.clone()], + ); + + // Register parachain + runtime + .block_on( + alice.register_parachain( + para_id, + cumulus_test_service::runtime::WASM_BINARY + .expect("You need to build the WASM binary to run this test!") + .to_vec(), + initial_head_data(para_id), + ), + ) + .unwrap(); + + // Run charlie as parachain collator + let charlie = runtime.block_on( + cumulus_test_service::TestNodeBuilder::new(para_id, tokio_handle.clone(), Charlie) + .enable_collator() + .connect_to_relay_chain_nodes(vec![&alice, &bob]) + .build(), + ); + + // Run dave as parachain collator + let dave = runtime.block_on( + cumulus_test_service::TestNodeBuilder::new(para_id, tokio_handle.clone(), Dave) + .enable_collator() + .connect_to_parachain_node(&charlie) + .connect_to_relay_chain_nodes(vec![&alice, &bob]) + .build(), + ); + + runtime.block_on(dave.wait_for_blocks(1)); + + let mut group = c.benchmark_group("Transaction pool"); + let account_num = 10; + let extrinsics_per_account = 20; + group.sample_size(10); + group.throughput(Throughput::Elements(account_num as u64 * extrinsics_per_account as u64)); + + let accounts = create_accounts(account_num); + let mut counter = 1; + + let benchmark_handle = tokio_handle.clone(); + group.bench_function( + format!("{} transfers from {} accounts", account_num * extrinsics_per_account, account_num), + |b| { + b.iter_batched( + || { + let prepare_extrinsics = create_account_extrinsics(&*dave.client, &accounts); + + benchmark_handle.block_on(future::join_all( + prepare_extrinsics.into_iter().map(|tx| { + submit_tx_and_wait_for_inclusion( + &dave.transaction_pool, + tx, + &*dave.client, + true, + ) + }), + )); + + create_benchmark_extrinsics(&*dave.client, &accounts, extrinsics_per_account) + }, + |extrinsics| { + benchmark_handle.block_on(future::join_all(extrinsics.into_iter().map(|tx| { + submit_tx_and_wait_for_inclusion( + &dave.transaction_pool, + tx, + &*dave.client, + false, + ) + }))); + + println!("Finished {}", counter); + counter += 1; + }, + BatchSize::SmallInput, + ) + }, + ); +} + +criterion_group!(benches, transaction_throughput_benchmarks); +criterion_main!(benches); diff --git a/test/service/src/chain_spec.rs b/test/service/src/chain_spec.rs index db65733706..1342df422c 100644 --- a/test/service/src/chain_spec.rs +++ b/test/service/src/chain_spec.rs @@ -25,7 +25,27 @@ use sp_core::{sr25519, Pair, Public}; use sp_runtime::traits::{IdentifyAccount, Verify}; /// Specialized `ChainSpec` for the normal parachain runtime. -pub type ChainSpec = sc_service::GenericChainSpec; +pub type ChainSpec = sc_service::GenericChainSpec; + +/// Extension for the genesis config to add custom keys easily. +#[derive(serde::Serialize, serde::Deserialize)] +pub struct GenesisExt { + /// The runtime genesis config. + runtime_genesis_config: cumulus_test_runtime::GenesisConfig, + /// The parachain id. + para_id: ParaId, +} + +impl sp_runtime::BuildStorage for GenesisExt { + fn assimilate_storage(&self, storage: &mut sp_core::storage::Storage) -> Result<(), String> { + sp_state_machine::BasicExternalities::execute_with_storage(storage, || { + sp_io::storage::set(cumulus_test_runtime::TEST_RUNTIME_UPGRADE_KEY, &vec![1, 2, 3, 4]); + cumulus_test_runtime::ParachainId::set(&self.para_id); + }); + + self.runtime_genesis_config.assimilate_storage(storage) + } +} /// Helper function to generate a crypto pair from seed pub fn get_from_seed(seed: &str) -> ::Public { @@ -65,8 +85,8 @@ pub fn get_chain_spec(id: ParaId) -> ChainSpec { "Local Testnet", "local_testnet", ChainType::Local, - move || local_testnet_genesis(), - vec![], + move || GenesisExt { runtime_genesis_config: local_testnet_genesis(), para_id: id }, + Vec::new(), None, None, None, @@ -110,6 +130,7 @@ fn testnet_genesis( balances: cumulus_test_runtime::BalancesConfig { balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(), }, - sudo: cumulus_test_runtime::SudoConfig { key: root_key }, + sudo: cumulus_test_runtime::SudoConfig { key: Some(root_key) }, + transaction_payment: Default::default(), } } diff --git a/test/service/src/genesis.rs b/test/service/src/genesis.rs index fc922f6f11..cf46d11af7 100644 --- a/test/service/src/genesis.rs +++ b/test/service/src/genesis.rs @@ -24,7 +24,8 @@ use sp_runtime::traits::Block as BlockT; /// Returns the initial head data for a parachain ID. pub fn initial_head_data(para_id: ParaId) -> HeadData { let spec = Box::new(crate::chain_spec::get_chain_spec(para_id)); - let block: Block = generate_genesis_block(&(spec as Box<_>)).unwrap(); + let block: Block = + generate_genesis_block(&(spec as Box<_>), sp_runtime::StateVersion::V1).unwrap(); let genesis_state = block.header().encode(); genesis_state.into() } diff --git a/test/service/src/lib.rs b/test/service/src/lib.rs index 61ed0bb501..5022612d29 100644 --- a/test/service/src/lib.rs +++ b/test/service/src/lib.rs @@ -21,15 +21,21 @@ mod chain_spec; mod genesis; -use core::future::Future; +use std::{future::Future, time::Duration}; + use cumulus_client_consensus_common::{ParachainCandidate, ParachainConsensus}; use cumulus_client_network::BlockAnnounceValidator; use cumulus_client_service::{ prepare_node_config, start_collator, start_full_node, StartCollatorParams, StartFullNodeParams, }; use cumulus_primitives_core::ParaId; +use cumulus_relay_chain_local::RelayChainLocal; use cumulus_test_runtime::{Hash, Header, NodeBlock as Block, RuntimeApi}; + +use frame_system_rpc_runtime_api::AccountNonceApi; +use parking_lot::Mutex; use polkadot_primitives::v1::{CollatorPair, Hash as PHash, PersistedValidationData}; +use polkadot_service::ProvideRuntimeApi; use sc_client_api::execution_extensions::ExecutionStrategies; use sc_network::{config::TransportConfig, multiaddr, NetworkService}; use sc_service::{ @@ -98,6 +104,9 @@ pub type Client = TFullClient< sc_executor::NativeElseWasmExecutor, >; +/// Transaction pool type used by the test service +pub type TransactionPool = Arc>; + /// 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 @@ -119,6 +128,7 @@ pub fn new_partial( config.wasm_method, config.default_heap_pages, config.max_runtime_instances, + config.runtime_cache_size, ); let (client, backend, keystore_container, task_manager) = @@ -174,6 +184,7 @@ async fn start_node_impl( Arc, Arc>, RpcHandlers, + TransactionPool, )> where RB: Fn(Arc) -> Result, sc_service::Error> @@ -207,13 +218,17 @@ where let client = params.client.clone(); let backend = params.backend.clone(); - let block_announce_validator = BlockAnnounceValidator::new( + + let relay_chain_interface = Arc::new(RelayChainLocal::new( relay_chain_full_node.client.clone(), - para_id, - Box::new(relay_chain_full_node.network.clone()), relay_chain_full_node.backend.clone(), - relay_chain_full_node.client.clone(), - ); + Arc::new(Mutex::new(Box::new(relay_chain_full_node.network.clone()))), + relay_chain_full_node.overseer_handle.clone(), + )); + task_manager.add_child(relay_chain_full_node.task_manager); + + let block_announce_validator = + BlockAnnounceValidator::new(relay_chain_interface.clone(), para_id); let block_announce_validator_builder = move |_| Box::new(block_announce_validator) as Box<_>; let prometheus_registry = parachain_config.prometheus_registry().cloned(); @@ -225,7 +240,6 @@ where transaction_pool: transaction_pool.clone(), spawn_handle: task_manager.spawn_handle(), import_queue: import_queue.clone(), - on_demand: None, block_announce_validator_builder: Some(Box::new(block_announce_validator_builder)), warp_sync: None, })?; @@ -237,8 +251,6 @@ where }; let rpc_handlers = sc_service::spawn_tasks(sc_service::SpawnTasksParams { - on_demand: None, - remote_blockchain: None, rpc_extensions_builder, client: client.clone(), transaction_pool: transaction_pool.clone(), @@ -260,20 +272,18 @@ where .map(|w| (w)(announce_block.clone())) .unwrap_or_else(|| announce_block); + let relay_chain_interface_for_closure = relay_chain_interface.clone(); if let Some(collator_key) = collator_key { let parachain_consensus: Box> = match consensus { Consensus::RelayChain => { let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( task_manager.spawn_handle(), client.clone(), - transaction_pool, + transaction_pool.clone(), prometheus_registry.as_ref(), None, ); - - let relay_chain_client = relay_chain_full_node.client.clone(); - let relay_chain_backend = relay_chain_full_node.backend.clone(); - + let relay_chain_interface2 = relay_chain_interface_for_closure.clone(); Box::new(cumulus_client_consensus_relay_chain::RelayChainConsensus::new( para_id, proposer_factory, @@ -281,8 +291,7 @@ where let parachain_inherent = cumulus_primitives_parachain_inherent::ParachainInherentData::create_at( relay_parent, - &*relay_chain_client, - &*relay_chain_backend, + &relay_chain_interface_for_closure, &validation_data, para_id, ); @@ -299,16 +308,12 @@ where } }, client.clone(), - relay_chain_full_node.client.clone(), - relay_chain_full_node.backend.clone(), + relay_chain_interface2, )) }, Consensus::Null => Box::new(NullConsensus), }; - let relay_chain_full_node = - relay_chain_full_node.with_client(polkadot_test_service::TestClient); - let params = StartCollatorParams { block_status: client.clone(), announce_block, @@ -317,27 +322,20 @@ where task_manager: &mut task_manager, para_id, parachain_consensus, - relay_chain_full_node: cumulus_client_service::RFullNode { - relay_chain_full_node, - collator_key, - }, + relay_chain_interface, + collator_key, import_queue, + slot_duration: Duration::from_secs(6), }; start_collator(params).await?; } else { - let relay_chain_full_node = - relay_chain_full_node.with_client(polkadot_test_service::TestClient); - let params = StartFullNodeParams { client: client.clone(), announce_block, task_manager: &mut task_manager, para_id, - relay_chain_full_node: cumulus_client_service::RFullNode { - relay_chain_full_node, - collator_key: CollatorPair::generate().0, - }, + relay_chain_interface, }; start_full_node(params)?; @@ -345,7 +343,7 @@ where start_network.start_network(); - Ok((task_manager, client, network, rpc_handlers)) + Ok((task_manager, client, network, rpc_handlers, transaction_pool)) } /// A Cumulus test node instance used for testing. @@ -361,6 +359,8 @@ pub struct TestNode { pub addr: MultiaddrWithPeerId, /// RPCHandlers to make RPC queries. pub rpc_handlers: RpcHandlers, + /// Node's transaction pool + pub transaction_pool: TransactionPool, } enum Consensus { @@ -519,7 +519,7 @@ impl TestNodeBuilder { format!("{} (relay chain)", relay_chain_config.network.node_name); let multiaddr = parachain_config.network.listen_addresses[0].clone(); - let (task_manager, client, network, rpc_handlers) = start_node_impl( + let (task_manager, client, network, rpc_handlers, transaction_pool) = start_node_impl( parachain_config, self.collator_key, relay_chain_config, @@ -534,7 +534,7 @@ impl TestNodeBuilder { let peer_id = network.local_peer_id().clone(); let addr = MultiaddrWithPeerId { multiaddr, peer_id }; - TestNode { task_manager, client, network, addr, rpc_handlers } + TestNode { task_manager, client, network, addr, rpc_handlers, transaction_pool } } } @@ -634,6 +634,7 @@ pub fn node_config( base_path: Some(base_path), informant_output_format: Default::default(), wasm_runtime_overrides: None, + runtime_cache_size: 2, }) } @@ -651,7 +652,7 @@ impl TestNode { function: impl Into, caller: Sr25519Keyring, ) -> Result { - let extrinsic = construct_extrinsic(&*self.client, function, caller); + let extrinsic = construct_extrinsic(&*self.client, function, caller.pair(), Some(0)); self.rpc_handlers.send_transaction(extrinsic.into()).await } @@ -669,23 +670,34 @@ impl TestNode { } } +/// Fetch account nonce for key pair +pub fn fetch_nonce(client: &Client, account: sp_core::sr25519::Public) -> u32 { + let best_hash = client.chain_info().best_hash; + client + .runtime_api() + .account_nonce(&generic::BlockId::Hash(best_hash), account.into()) + .expect("Fetching account nonce works; qed") +} + /// Construct an extrinsic that can be applied to the test runtime. pub fn construct_extrinsic( client: &Client, function: impl Into, - caller: Sr25519Keyring, + caller: sp_core::sr25519::Pair, + nonce: Option, ) -> runtime::UncheckedExtrinsic { let function = function.into(); let current_block_hash = client.info().best_hash; let current_block = client.info().best_number.saturated_into(); let genesis_block = client.hash(0).unwrap().unwrap(); - let nonce = 0; + let nonce = nonce.unwrap_or_else(|| fetch_nonce(client, caller.public())); let period = runtime::BlockHashCount::get() .checked_next_power_of_two() .map(|c| c / 2) .unwrap_or(2) as u64; let tip = 0; let extra: runtime::SignedExtra = ( + frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckGenesis::::new(), frame_system::CheckEra::::from(generic::Era::mortal( @@ -699,7 +711,7 @@ pub fn construct_extrinsic( let raw_payload = runtime::SignedPayload::from_raw( function.clone(), extra.clone(), - (runtime::VERSION.spec_version, genesis_block, current_block_hash, (), (), ()), + ((), runtime::VERSION.spec_version, genesis_block, current_block_hash, (), (), ()), ); let signature = raw_payload.using_encoded(|e| caller.sign(e)); runtime::UncheckedExtrinsic::new_signed( diff --git a/test/service/tests/integration.rs b/test/service/tests/integration.rs index e78405473d..2687a51084 100644 --- a/test/service/tests/integration.rs +++ b/test/service/tests/integration.rs @@ -16,7 +16,6 @@ use cumulus_primitives_core::ParaId; use cumulus_test_service::{initial_head_data, run_relay_chain_validator_node, Keyring::*}; -use futures::join; #[substrate_test_utils::test] #[ignore] @@ -30,7 +29,7 @@ async fn test_collating_and_non_collator_mode_catching_up() { let tokio_handle = tokio::runtime::Handle::current(); // start alice - let alice = run_relay_chain_validator_node(tokio_handle.clone(), Alice, || {}, vec![]); + let alice = run_relay_chain_validator_node(tokio_handle.clone(), Alice, || {}, Vec::new()); // start bob let bob = @@ -64,11 +63,4 @@ async fn test_collating_and_non_collator_mode_catching_up() { .build() .await; dave.wait_for_blocks(7).await; - - join!( - alice.task_manager.clean_shutdown(), - bob.task_manager.clean_shutdown(), - charlie.task_manager.clean_shutdown(), - dave.task_manager.clean_shutdown(), - ); } diff --git a/test/service/tests/runtime_upgrade.rs b/test/service/tests/runtime_upgrade.rs index f59527e3be..4731404fee 100644 --- a/test/service/tests/runtime_upgrade.rs +++ b/test/service/tests/runtime_upgrade.rs @@ -16,7 +16,7 @@ use cumulus_primitives_core::ParaId; use cumulus_test_service::{initial_head_data, run_relay_chain_validator_node, Keyring::*}; -use futures::{join, StreamExt}; +use futures::StreamExt; use sc_client_api::BlockchainEvents; use sp_runtime::generic::BlockId; @@ -31,7 +31,7 @@ async fn test_runtime_upgrade() { let tokio_handle = tokio::runtime::Handle::current(); // start alice - let alice = run_relay_chain_validator_node(tokio_handle.clone(), Alice, || {}, vec![]); + let alice = run_relay_chain_validator_node(tokio_handle.clone(), Alice, || {}, Vec::new()); // start bob let bob = @@ -73,17 +73,11 @@ async fn test_runtime_upgrade() { .expect("Runtime version exists"); expected_runtime_version.spec_version += 1; - // Replace the runtime version in the WASM blob to make it look like a new runtime. - let wasm = sp_maybe_compressed_blob::decompress( - cumulus_test_runtime_upgrade::WASM_BINARY.unwrap(), - sp_maybe_compressed_blob::CODE_BLOB_BOMB_LIMIT, - ) - .expect("Decompressing the WASM blob works"); - let wasm = sp_version::embed::embed_runtime_version(&wasm, expected_runtime_version.clone()) - .expect("Embedding the runtime version works"); + let wasm = cumulus_test_runtime::wasm_spec_version_incremented::WASM_BINARY + .expect("Wasm binary with incremented spec version should have been built"); // schedule runtime upgrade - charlie.schedule_upgrade(wasm).await.unwrap(); + charlie.schedule_upgrade(wasm.into()).await.unwrap(); let mut import_stream = dave.client.import_notification_stream(); @@ -99,11 +93,4 @@ async fn test_runtime_upgrade() { } } } - - join!( - alice.task_manager.clean_shutdown(), - bob.task_manager.clean_shutdown(), - charlie.task_manager.clean_shutdown(), - dave.task_manager.clean_shutdown(), - ); }