diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index f64e6c0580..e0a517ab06 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -21,7 +21,7 @@ RUN rm /usr/bin/cc && ln -s /usr/bin/clang /usr/bin/cc # Install protoc - protobuf compiler # The one shipped with Alpine does not work ARG TARGETARCH -ARG PROTOC_VERSION=25.2 +ARG PROTOC_VERSION=27.3 RUN if [[ "$TARGETARCH" == "arm64" ]] ; then export PROTOC_ARCH=aarch_64; else export PROTOC_ARCH=x86_64; fi; \ curl -Ls https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-linux-${PROTOC_ARCH}.zip \ -o /tmp/protoc.zip && \ @@ -29,10 +29,10 @@ RUN if [[ "$TARGETARCH" == "arm64" ]] ; then export PROTOC_ARCH=aarch_64; else e rm /tmp/protoc.zip && \ ln -s /opt/protoc/bin/protoc /usr/bin/ -# Install protoc v25.2+ -RUN curl -OL https://github.com/protocolbuffers/protobuf/releases/download/v25.2/protoc-25.2-linux-x86_64.zip \ - && unzip protoc-25.2-linux-x86_64.zip -d /usr/local \ - && rm protoc-25.2-linux-x86_64.zip +# Install protoc +RUN curl -OL https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-linux-x86_64.zip \ + && unzip protoc-${PROTOC_VERSION}-linux-x86_64.zip -d /usr/local \ + && rm protoc-${PROTOC_VERSION}-linux-x86_64.zip # Switch to vscode user USER vscode diff --git a/.github/actions/rust/action.yaml b/.github/actions/rust/action.yaml index cdfc7e11e6..8854007013 100644 --- a/.github/actions/rust/action.yaml +++ b/.github/actions/rust/action.yaml @@ -79,7 +79,7 @@ runs: shell: bash run: | curl -Lo /tmp/protoc.zip \ - "https://github.com/protocolbuffers/protobuf/releases/download/v25.2/protoc-25.2-linux-${{ steps.protoc_arch.outputs.arch }}.zip" + "https://github.com/protocolbuffers/protobuf/releases/download/v27.3/protoc-27.3-linux-${{ steps.protoc_arch.outputs.arch }}.zip" unzip -o /tmp/protoc.zip -d ${HOME}/.local echo "PROTOC=${HOME}/.local/bin/protoc" >> $GITHUB_ENV export PATH="${PATH}:${HOME}/.local/bin" diff --git a/.pnp.cjs b/.pnp.cjs index 7b11ce621c..0a13a010d1 100755 --- a/.pnp.cjs +++ b/.pnp.cjs @@ -2551,7 +2551,7 @@ const RAW_RUNTIME_STATE = "packageLocation": "./packages/bench-suite/",\ "packageDependencies": [\ ["@dashevo/bench-suite", "workspace:packages/bench-suite"],\ - ["@dashevo/dashcore-lib", "npm:0.21.3"],\ + ["@dashevo/dashcore-lib", "npm:0.22.0"],\ ["@dashevo/dpns-contract", "workspace:packages/dpns-contract"],\ ["@dashevo/wallet-lib", "workspace:packages/wallet-lib"],\ ["@dashevo/wasm-dpp", "workspace:packages/wasm-dpp"],\ @@ -2589,7 +2589,7 @@ const RAW_RUNTIME_STATE = ["@dashevo/bls", "npm:1.2.9"],\ ["@dashevo/dapi-client", "workspace:packages/js-dapi-client"],\ ["@dashevo/dapi-grpc", "workspace:packages/dapi-grpc"],\ - ["@dashevo/dashcore-lib", "npm:0.21.3"],\ + ["@dashevo/dashcore-lib", "npm:0.22.0"],\ ["@dashevo/dashd-rpc", "npm:19.0.0"],\ ["@dashevo/dp-services-ctl", "https://github.com/dashevo/js-dp-services-ctl.git#commit=3976076b0018c5b4632ceda4c752fc597f27a640"],\ ["@dashevo/grpc-common", "workspace:packages/js-grpc-common"],\ @@ -2634,7 +2634,7 @@ const RAW_RUNTIME_STATE = ["@babel/core", "npm:7.23.3"],\ ["@dashevo/dapi-grpc", "workspace:packages/dapi-grpc"],\ ["@dashevo/dash-spv", "workspace:packages/dash-spv"],\ - ["@dashevo/dashcore-lib", "npm:0.21.3"],\ + ["@dashevo/dashcore-lib", "npm:0.22.0"],\ ["@dashevo/grpc-common", "workspace:packages/js-grpc-common"],\ ["@dashevo/wasm-dpp", "workspace:packages/wasm-dpp"],\ ["assert-browserify", "npm:2.0.0"],\ @@ -2726,7 +2726,7 @@ const RAW_RUNTIME_STATE = ["@dashevo/dash-spv", "workspace:packages/dash-spv"],\ ["@dashevo/dark-gravity-wave", "npm:1.1.1"],\ ["@dashevo/dash-util", "npm:2.0.3"],\ - ["@dashevo/dashcore-lib", "npm:0.21.3"],\ + ["@dashevo/dashcore-lib", "npm:0.22.0"],\ ["chai", "npm:4.3.10"],\ ["eslint", "npm:8.53.0"],\ ["eslint-config-airbnb-base", "virtual:e2d057e7cc143d3cb9bec864f4a2d862441b5a09f81f8e6c46e7a098cbc89e4d07017cc6e2e2142d5704bb55da853cbec2d025ebc0b30e8696c31380c00f2c7d#npm:15.0.0"],\ @@ -2753,10 +2753,10 @@ const RAW_RUNTIME_STATE = }]\ ]],\ ["@dashevo/dashcore-lib", [\ - ["npm:0.21.3", {\ - "packageLocation": "./.yarn/cache/@dashevo-dashcore-lib-npm-0.21.3-8c8abba924-28e2731ac6.zip/node_modules/@dashevo/dashcore-lib/",\ + ["npm:0.22.0", {\ + "packageLocation": "./.yarn/cache/@dashevo-dashcore-lib-npm-0.22.0-9a6dd273b9-ac9e268f6e.zip/node_modules/@dashevo/dashcore-lib/",\ "packageDependencies": [\ - ["@dashevo/dashcore-lib", "npm:0.21.3"],\ + ["@dashevo/dashcore-lib", "npm:0.22.0"],\ ["@dashevo/bls", "npm:1.2.9"],\ ["@dashevo/x11-hash-js", "npm:1.0.2"],\ ["@types/node", "npm:12.20.37"],\ @@ -2939,7 +2939,7 @@ const RAW_RUNTIME_STATE = "packageDependencies": [\ ["@dashevo/platform-test-suite", "workspace:packages/platform-test-suite"],\ ["@dashevo/dapi-client", "workspace:packages/js-dapi-client"],\ - ["@dashevo/dashcore-lib", "npm:0.21.3"],\ + ["@dashevo/dashcore-lib", "npm:0.22.0"],\ ["@dashevo/dpns-contract", "workspace:packages/dpns-contract"],\ ["@dashevo/feature-flags-contract", "workspace:packages/feature-flags-contract"],\ ["@dashevo/grpc-common", "workspace:packages/js-grpc-common"],\ @@ -3034,7 +3034,7 @@ const RAW_RUNTIME_STATE = ["@dashevo/wallet-lib", "workspace:packages/wallet-lib"],\ ["@dashevo/dapi-client", "workspace:packages/js-dapi-client"],\ ["@dashevo/dash-spv", "workspace:packages/dash-spv"],\ - ["@dashevo/dashcore-lib", "npm:0.21.3"],\ + ["@dashevo/dashcore-lib", "npm:0.22.0"],\ ["@dashevo/grpc-common", "workspace:packages/js-grpc-common"],\ ["@dashevo/wasm-dpp", "workspace:packages/wasm-dpp"],\ ["@yarnpkg/pnpify", "npm:4.0.0-rc.42"],\ @@ -3096,7 +3096,7 @@ const RAW_RUNTIME_STATE = ["@babel/core", "npm:7.23.3"],\ ["@babel/preset-env", "virtual:e2d057e7cc143d3cb9bec864f4a2d862441b5a09f81f8e6c46e7a098cbc89e4d07017cc6e2e2142d5704bb55da853cbec2d025ebc0b30e8696c31380c00f2c7d#npm:7.23.3"],\ ["@dashevo/bls", "npm:1.2.9"],\ - ["@dashevo/dashcore-lib", "npm:0.21.3"],\ + ["@dashevo/dashcore-lib", "npm:0.22.0"],\ ["@dashevo/dpns-contract", "workspace:packages/dpns-contract"],\ ["@types/bs58", "npm:4.0.1"],\ ["@types/node", "npm:14.17.34"],\ @@ -8269,10 +8269,10 @@ const RAW_RUNTIME_STATE = }]\ ]],\ ["cookie", [\ - ["npm:0.4.1", {\ - "packageLocation": "./.yarn/cache/cookie-npm-0.4.1-cc5e2ebb42-0f2defd60a.zip/node_modules/cookie/",\ + ["npm:0.7.1", {\ + "packageLocation": "./.yarn/cache/cookie-npm-0.7.1-f01524ff99-aec6a6aa07.zip/node_modules/cookie/",\ "packageDependencies": [\ - ["cookie", "npm:0.4.1"]\ + ["cookie", "npm:0.7.1"]\ ],\ "linkType": "HARD"\ }]\ @@ -8473,7 +8473,7 @@ const RAW_RUNTIME_STATE = ["@dashevo/bls", "npm:1.2.9"],\ ["@dashevo/dapi-client", "workspace:packages/js-dapi-client"],\ ["@dashevo/dapi-grpc", "workspace:packages/dapi-grpc"],\ - ["@dashevo/dashcore-lib", "npm:0.21.3"],\ + ["@dashevo/dashcore-lib", "npm:0.22.0"],\ ["@dashevo/dashpay-contract", "workspace:packages/dashpay-contract"],\ ["@dashevo/dpns-contract", "workspace:packages/dpns-contract"],\ ["@dashevo/grpc-common", "workspace:packages/js-grpc-common"],\ @@ -8552,7 +8552,7 @@ const RAW_RUNTIME_STATE = ["@babel/eslint-parser", "virtual:6c6296bde00603e266f7d80babe1e01aa0c19f626934f58fe08f890a291bb1a38fcee25bf30c24857d5cfba290f01209decc48384318fd6815c5a514cb48be25#npm:7.23.3"],\ ["@dashevo/bls", "npm:1.2.9"],\ ["@dashevo/dapi-client", "workspace:packages/js-dapi-client"],\ - ["@dashevo/dashcore-lib", "npm:0.21.3"],\ + ["@dashevo/dashcore-lib", "npm:0.22.0"],\ ["@dashevo/dashd-rpc", "npm:19.0.0"],\ ["@dashevo/docker-compose", "npm:0.24.4"],\ ["@dashevo/wallet-lib", "workspace:packages/wallet-lib"],\ @@ -9365,7 +9365,7 @@ const RAW_RUNTIME_STATE = ["@types/node", "npm:18.16.1"],\ ["accepts", "npm:1.3.7"],\ ["base64id", "npm:2.0.0"],\ - ["cookie", "npm:0.4.1"],\ + ["cookie", "npm:0.7.1"],\ ["cors", "npm:2.8.5"],\ ["debug", "virtual:4b12ba5111caf7e8338099bdbc7cb046a9f8e079a44e74d0c03dca469876e3071ebbe671c5e90ae6b78ae33e22c205fa5ed32169a4aabd1404b13c56d09986e1#npm:4.3.4"],\ ["engine.io-parser", "npm:5.0.4"],\ diff --git a/.yarn/cache/@dashevo-dashcore-lib-npm-0.21.3-8c8abba924-28e2731ac6.zip b/.yarn/cache/@dashevo-dashcore-lib-npm-0.21.3-8c8abba924-28e2731ac6.zip deleted file mode 100644 index f9ac0cfb72..0000000000 Binary files a/.yarn/cache/@dashevo-dashcore-lib-npm-0.21.3-8c8abba924-28e2731ac6.zip and /dev/null differ diff --git a/.yarn/cache/@dashevo-dashcore-lib-npm-0.22.0-9a6dd273b9-ac9e268f6e.zip b/.yarn/cache/@dashevo-dashcore-lib-npm-0.22.0-9a6dd273b9-ac9e268f6e.zip new file mode 100644 index 0000000000..909a68aca0 Binary files /dev/null and b/.yarn/cache/@dashevo-dashcore-lib-npm-0.22.0-9a6dd273b9-ac9e268f6e.zip differ diff --git a/.yarn/cache/cookie-npm-0.4.1-cc5e2ebb42-0f2defd60a.zip b/.yarn/cache/cookie-npm-0.4.1-cc5e2ebb42-0f2defd60a.zip deleted file mode 100644 index 2796ed2bc9..0000000000 Binary files a/.yarn/cache/cookie-npm-0.4.1-cc5e2ebb42-0f2defd60a.zip and /dev/null differ diff --git a/.yarn/cache/cookie-npm-0.7.1-f01524ff99-aec6a6aa07.zip b/.yarn/cache/cookie-npm-0.7.1-f01524ff99-aec6a6aa07.zip new file mode 100644 index 0000000000..26c6c93fd8 Binary files /dev/null and b/.yarn/cache/cookie-npm-0.7.1-f01524ff99-aec6a6aa07.zip differ diff --git a/.yarnrc.yml b/.yarnrc.yml index 34231a77e3..dd002648b0 100644 --- a/.yarnrc.yml +++ b/.yarnrc.yml @@ -15,6 +15,7 @@ npmAuditExcludePackages: - "@humanwhocodes/config-array" # TODO: Update eslint - "@humanwhocodes/object-schema" # TODO: Update eslint - micromatch # TODO: remove when new micromatch will be released https://github.com/advisories/GHSA-952p-6rrq-rcjv + - eslint # TODO: Update eslint https://github.com/dashpay/platform/issues/2212 packageExtensions: "@dashevo/protobufjs@*": diff --git a/CHANGELOG.md b/CHANGELOG.md index 42467f4388..f90a4979b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,193 @@ +### [1.4.1](https://github.com/dashpay/platform/compare/v1.4.0...v1.4.1) (2024-10-12) + + +### ⚠ BREAKING CHANGES + +* **sdk:** improve mock context provider async processing (#2232) + +### Bug Fixes + +* **sdk:** testnet chain sync failed ([#2236](https://github.com/dashpay/platform/issues/2236)) + + +### Miscellaneous Chores + +* add some extra unit tests + + +### Code Refactoring + +* minor fixes and extra comments +* **sdk:** improve mock context provider async processing ([#2232](https://github.com/dashpay/platform/issues/2232)) + +## [1.4.0](https://github.com/dashpay/platform/compare/v1.4.0-dev.8...v1.4.0) (2024-10-10) + + +### Features + +* **dpp:** added identity public key private key validation methods ([#2235](https://github.com/dashpay/platform/issues/2235)) +* **sdk:** fix client tls connections ([#2223](https://github.com/dashpay/platform/issues/2223)) +* **dpp:** add a convenience method to get the public key data for a private key depending on the key type ([#2214](https://github.com/dashpay/platform/issues/2214)) +* **platform:** add owner keys to identities, fixed verification of use of owner keys ([#2215](https://github.com/dashpay/platform/issues/2215)) +* **sdk:** enable withdrawals v1 in JS SDK ([#2201](https://github.com/dashpay/platform/issues/2201)) +* start network with latest version if genesis version not set ([#2206](https://github.com/dashpay/platform/issues/2206)) +* **dashmate:** confirm a node reset ([#2160](https://github.com/dashpay/platform/issues/2160)) +* **platform:** do not switch to oldest quorums in validator set update ([#2167](https://github.com/dashpay/platform/issues/2167)) +* **platform:** get current quorum info ([#2168](https://github.com/dashpay/platform/issues/2168)) +* **platform:** withdrawals polishing and fixes for mainnet ([#2166](https://github.com/dashpay/platform/issues/2166)) +* **sdk:** change default network to mainnet ([#2161](https://github.com/dashpay/platform/issues/2161)) + + +### Bug Fixes + +* **sdk:** added signing_withdrawal_key_to_use to withdraw sdk call ([#2234](https://github.com/dashpay/platform/issues/2234)) +* **platform:** fixed Platform State deserialization issue ([#2227](https://github.com/dashpay/platform/issues/2227)) +* cookie accepts cookie name, path, and domain with out of bounds characters ([#2211](https://github.com/dashpay/platform/issues/2211)) +* **drive:** set sign height when rebroadcasting ([#2210](https://github.com/dashpay/platform/issues/2210)) +* **sdk:** small sdk improvements and fixes for v1.4 ([#2200](https://github.com/dashpay/platform/issues/2200)) +* **drive-abci:** fix network upgrade to version 4 ([#2189](https://github.com/dashpay/platform/issues/2189)) +* **dashmate:** collect docker stats in the doctor command ([#2180](https://github.com/dashpay/platform/issues/2180)) +* **dashmate:** validate external IP ([#2183](https://github.com/dashpay/platform/issues/2183)) +* **platform:** matched withdrawal fees to actual processing cost ([#2186](https://github.com/dashpay/platform/issues/2186)) +* **platform:** withdrawal automatic retries after core rejection ([#2185](https://github.com/dashpay/platform/issues/2185)) +* **platform:** withdrawal limits ([#2182](https://github.com/dashpay/platform/issues/2182)) +* **sdk:** get node status ([#2139](https://github.com/dashpay/platform/issues/2139)) +* **dapi:** getStatus cache invalidation ([#2155](https://github.com/dashpay/platform/issues/2155)) +* **dapi:** invalid mainnet seed ports ([#2173](https://github.com/dashpay/platform/issues/2173)) +* **dashmate:** cannot read properties of undefined (reading 'expires') ([#2164](https://github.com/dashpay/platform/issues/2164)) +* **dashmate:** colors[updated] is not a function ([#2157](https://github.com/dashpay/platform/issues/2157)) +* **dashmate:** doctor fails collecting to big logs ([#2158](https://github.com/dashpay/platform/issues/2158)) +* **dashmate:** port marks as closed if ipv6 is not disabled ([#2162](https://github.com/dashpay/platform/issues/2162)) +* **dashmate:** remove confusing short flag name ([#2165](https://github.com/dashpay/platform/issues/2165)) + + +### Miscellaneous Chores + +* **dpp:** add method for decoding identifier with unknown string encoding ([#2230](https://github.com/dashpay/platform/issues/2230)) +* **drive:** log invalid state on deserialisation ([#2220](https://github.com/dashpay/platform/issues/2220)) +* **sdk:** expose drive module in public API for rs-sdk ([#2217](https://github.com/dashpay/platform/issues/2217)) +* update dependences ([#2072](https://github.com/dashpay/platform/issues/2072)) +* bump GroveDB dependency ([#2196](https://github.com/dashpay/platform/issues/2196)) +* **drive:** improve withdrawal logging ([#2203](https://github.com/dashpay/platform/issues/2203)) +* **drive:** logs and metrics for withdrawal daily limit ([#2192](https://github.com/dashpay/platform/issues/2192)) +* **release:** replace colima with native docker in macOS builds ([#2188](https://github.com/dashpay/platform/issues/2188)) +* **dashmate:** do not call mint on masternodes ([#2172](https://github.com/dashpay/platform/issues/2172)) +* **platform:** protocol version 4 creation ([#2153](https://github.com/dashpay/platform/issues/2153)) + + +### Code Refactoring + +* **sdk:** contested resource as struct type ([#2225](https://github.com/dashpay/platform/issues/2225)) +* **drive:** remove duplicated withdrawal amount validation ([#2191](https://github.com/dashpay/platform/issues/2191)) + + +### Build System + +* devcontainer support ([#2179](https://github.com/dashpay/platform/issues/2179)) + + +### Continuous Integration + +* prebuild dev containers ([#2184](https://github.com/dashpay/platform/issues/2184)) +* build dashmate on macos14 + + +### Tests + +* **test-suite:** enable withdrawal tests ([#2202](https://github.com/dashpay/platform/issues/2202)) +* **dashmate:** e2e tests failing due to DKG interval check ([#2171](https://github.com/dashpay/platform/issues/2171)) + + +### Documentation + +* **dashmate:** document logging configuration ([#2156](https://github.com/dashpay/platform/issues/2156)) +* update README ([#2219](https://github.com/dashpay/platform/issues/2219)) + + +### ⚠ BREAKING CHANGES + +* **platform:** add owner keys to identities, fixed verification of use of owner keys. While these are breaking changes, they will only happen in Protocol V4. (#2215) +* **platform:** matched withdrawal fees to actual processing cost. Since fees change it is is a breaking change that will take effect in v4 of the protocol. (#2186) +* **platform:** withdrawal automatic retries after core rejection. This is a breaking change that will be marked as active in v1.4 (#2185) +* **platform:** withdrawal limits. This is breaking, and will be activated in version 1.4 (#2182) +* **sdk:** Now if network is not specified, JS SDK will connect to mainnet. (#2161) +* **dashmate:** confirm a node reset. This change will break any non interactive execution of reset command so now the force flag must be provided to skip the reset confirmation. (#2160) +* **platform:** withdrawals polishing and fixes for mainnet. Updating in V4 hard fork. (#2166) +* **platform:** do not switch to oldest quorums in validator set update. This is included as a change in protocol version 4. (#2167) + + +## [1.4.0-dev.8](https://github.com/dashpay/platform/compare/v1.4.0-dev.7...v1.4.0-dev.8) (2024-10-08) + + +### Features + +* **sdk:** fix client tls connections ([#2223](https://github.com/dashpay/platform/issues/2223)) + + +### Bug Fixes + +* **platform:** fixed Platform State deserialization issue ([#2227](https://github.com/dashpay/platform/issues/2227)) + +## [1.4.0-dev.7](https://github.com/dashpay/platform/compare/v1.4.0-dev.6...v1.4.0-dev.7) (2024-10-07) + + +### Miscellaneous Chores + +* **drive:** log invalid state on deserialisation ([#2220](https://github.com/dashpay/platform/issues/2220)) + +## [1.4.0-dev.6](https://github.com/dashpay/platform/compare/v1.4.0-dev.5...v1.4.0-dev.6) (2024-10-07) + + +### Miscellaneous Chores + +* **sdk:** expose drive module in public API for rs-sdk ([#2217](https://github.com/dashpay/platform/issues/2217)) +* update dependences ([#2072](https://github.com/dashpay/platform/issues/2072)) + +## [1.4.0-dev.5](https://github.com/dashpay/platform/compare/v1.4.0-dev.4...v1.4.0-dev.5) (2024-10-07) + + +### ⚠ BREAKING CHANGES + +* **platform:** add owner keys to identities, fixed verification of use of owner keys (#2215) + +### Features + +* **dpp:** add a convenience method to get the public key data for a private key depending on the key type ([#2214](https://github.com/dashpay/platform/issues/2214)) +* **platform:** add owner keys to identities, fixed verification of use of owner keys ([#2215](https://github.com/dashpay/platform/issues/2215)) + +## [1.4.0-dev.4](https://github.com/dashpay/platform/compare/v1.4.0-dev.3...v1.4.0-dev.4) (2024-10-05) + + +### Features + +* **sdk:** enable withdrawals v1 in JS SDK ([#2201](https://github.com/dashpay/platform/issues/2201)) +* start network with latest version if genesis version not set ([#2206](https://github.com/dashpay/platform/issues/2206)) + + +### Bug Fixes + +* cookie accepts cookie name, path, and domain with out of bounds characters ([#2211](https://github.com/dashpay/platform/issues/2211)) +* **drive:** set sign height when rebroadcasting ([#2210](https://github.com/dashpay/platform/issues/2210)) +* **sdk:** small sdk improvements and fixes for v1.4 ([#2200](https://github.com/dashpay/platform/issues/2200)) + + +### Code Refactoring + +* **drive:** remove duplicated withdrawal amount validation ([#2191](https://github.com/dashpay/platform/issues/2191)) + + +### Miscellaneous Chores + +* bump GroveDB dependency ([#2196](https://github.com/dashpay/platform/issues/2196)) +* **drive:** improve withdrawal logging ([#2203](https://github.com/dashpay/platform/issues/2203)) +* **drive:** logs and metrics for withdrawal daily limit ([#2192](https://github.com/dashpay/platform/issues/2192)) +* **release:** replace colima with native docker in macOS builds ([#2188](https://github.com/dashpay/platform/issues/2188)) + + +### Tests + +* **test-suite:** enable withdrawal tests ([#2202](https://github.com/dashpay/platform/issues/2202)) + ## [1.4.0-dev.2](https://github.com/dashpay/platform/compare/v1.4.0-dev.1...v1.4.0-dev.2) (2024-09-30) diff --git a/Cargo.lock b/Cargo.lock index dc4f8a653e..518b077b81 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -89,6 +89,12 @@ dependencies = [ "libc", ] +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + [[package]] name = "anstream" version = "0.6.15" @@ -177,33 +183,15 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" -[[package]] -name = "async-io" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" -dependencies = [ - "async-lock", - "autocfg", - "cfg-if", - "concurrent-queue", - "futures-lite", - "log", - "parking", - "polling", - "rustix 0.37.27", - "slab", - "socket2 0.4.10", - "waker-fn", -] - [[package]] name = "async-lock" -version = "2.8.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" dependencies = [ "event-listener", + "event-listener-strategy", + "pin-project-lite", ] [[package]] @@ -245,51 +233,12 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", -] - [[package]] name = "autocfg" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" -[[package]] -name = "axum" -version = "0.6.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" -dependencies = [ - "async-trait", - "axum-core 0.3.4", - "bitflags 1.3.2", - "bytes", - "futures-util", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.30", - "itoa", - "matchit", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "sync_wrapper 0.1.2", - "tower", - "tower-layer", - "tower-service", -] - [[package]] name = "axum" version = "0.7.5" @@ -297,14 +246,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" dependencies = [ "async-trait", - "axum-core 0.4.3", + "axum-core", "axum-macros", "bytes", "futures-util", - "http 1.1.0", - "http-body 1.0.1", + "http", + "http-body", "http-body-util", - "hyper 1.4.1", + "hyper", "hyper-util", "itoa", "matchit", @@ -325,23 +274,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "axum-core" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" -dependencies = [ - "async-trait", - "bytes", - "futures-util", - "http 0.2.12", - "http-body 0.4.6", - "mime", - "rustversion", - "tower-layer", - "tower-service", -] - [[package]] name = "axum-core" version = "0.4.3" @@ -351,8 +283,8 @@ dependencies = [ "async-trait", "bytes", "futures-util", - "http 1.1.0", - "http-body 1.0.1", + "http", + "http-body", "http-body-util", "mime", "pin-project-lite", @@ -377,13 +309,12 @@ dependencies = [ [[package]] name = "backon" -version = "0.4.4" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d67782c3f868daa71d3533538e98a8e13713231969def7536e8039606fc46bf0" +checksum = "e4fa97bb310c33c811334143cf64c5bb2b7b3c06e453db6b095d7061eff8f113" dependencies = [ - "fastrand 2.1.0", - "futures-core", - "pin-project", + "fastrand", + "gloo-timers", "tokio", ] @@ -464,7 +395,7 @@ dependencies = [ "lazycell", "log", "peeking_take_while", - "prettyplease 0.2.20", + "prettyplease", "proc-macro2", "quote", "regex", @@ -625,12 +556,6 @@ dependencies = [ "syn_derive", ] -[[package]] -name = "bs58" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" - [[package]] name = "bs58" version = "0.5.1" @@ -710,37 +635,6 @@ dependencies = [ "pkg-config", ] -[[package]] -name = "camino" -version = "1.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo-platform" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo_metadata" -version = "0.14.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" -dependencies = [ - "camino", - "cargo-platform", - "semver", - "serde", - "serde_json", -] - [[package]] name = "cast" version = "0.3.0" @@ -781,7 +675,7 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "check-features" -version = "1.4.0-dev.3" +version = "1.4.1" dependencies = [ "toml", ] @@ -806,8 +700,19 @@ name = "ciborium" version = "0.2.0" source = "git+https://github.com/qrayven/ciborium?branch=feat-ser-null-as-undefined#5fbba76d132caf04cd1f271336d9daafdc747f10" dependencies = [ - "ciborium-io", - "ciborium-ll", + "ciborium-io 0.2.0", + "ciborium-ll 0.2.0", + "serde", +] + +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io 0.2.2", + "ciborium-ll 0.2.2", "serde", ] @@ -816,13 +721,29 @@ name = "ciborium-io" version = "0.2.0" source = "git+https://github.com/qrayven/ciborium?branch=feat-ser-null-as-undefined#5fbba76d132caf04cd1f271336d9daafdc747f10" +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + [[package]] name = "ciborium-ll" version = "0.2.0" source = "git+https://github.com/qrayven/ciborium?branch=feat-ser-null-as-undefined#5fbba76d132caf04cd1f271336d9daafdc747f10" dependencies = [ - "ciborium-io", - "half", + "ciborium-io 0.2.0", + "half 1.8.3", +] + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io 0.2.2", + "half 2.4.1", ] [[package]] @@ -846,17 +767,6 @@ dependencies = [ "libloading", ] -[[package]] -name = "clap" -version = "2.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" -dependencies = [ - "bitflags 1.3.2", - "textwrap", - "unicode-width", -] - [[package]] name = "clap" version = "4.5.16" @@ -924,22 +834,22 @@ dependencies = [ [[package]] name = "console-api" -version = "0.6.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd326812b3fd01da5bb1af7d340d0d555fd3d4b641e7f1dfcf5962a902952787" +checksum = "86ed14aa9c9f927213c6e4f3ef75faaad3406134efe84ba2cb7983431d5f0931" dependencies = [ "futures-core", - "prost 0.12.6", - "prost-types 0.12.6", - "tonic 0.10.2", + "prost", + "prost-types", + "tonic", "tracing-core", ] [[package]] name = "console-subscriber" -version = "0.2.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7481d4c57092cd1c19dd541b92bdce883de840df30aa5d03fd48a3935c01842e" +checksum = "e2e3a111a37f3333946ebf9da370ba5c5577b18eb342ec683eb488dd21980302" dependencies = [ "console-api", "crossbeam-channel", @@ -947,13 +857,15 @@ dependencies = [ "futures-task", "hdrhistogram", "humantime", - "prost-types 0.12.6", + "hyper-util", + "prost", + "prost-types", "serde", "serde_json", "thread_local", "tokio", "tokio-stream", - "tonic 0.10.2", + "tonic", "tracing", "tracing-core", "tracing-subscriber", @@ -1019,24 +931,24 @@ dependencies = [ [[package]] name = "criterion" -version = "0.3.6" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f" +checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" dependencies = [ - "atty", + "anes", "cast", - "clap 2.34.0", + "ciborium 0.2.2", + "clap", "criterion-plot", - "csv", + "is-terminal", "itertools 0.10.5", - "lazy_static", "num-traits", + "once_cell", "oorandom", "plotters", "rayon", "regex", "serde", - "serde_cbor", "serde_derive", "serde_json", "tinytemplate", @@ -1045,9 +957,9 @@ dependencies = [ [[package]] name = "criterion-plot" -version = "0.4.5" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" dependencies = [ "cast", "itertools 0.10.5", @@ -1087,6 +999,12 @@ version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + [[package]] name = "crypto-common" version = "0.1.6" @@ -1097,27 +1015,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "csv" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe" -dependencies = [ - "csv-core", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "csv-core" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70" -dependencies = [ - "memchr", -] - [[package]] name = "curve25519-dalek" version = "4.1.3" @@ -1147,23 +1044,23 @@ dependencies = [ [[package]] name = "dapi-grpc" -version = "1.4.0-dev.3" +version = "1.4.1" dependencies = [ "dapi-grpc-macros", "futures-core", "platform-version", - "prost 0.12.6", + "prost", "serde", "serde_bytes", "serde_json", "tenderdash-proto", - "tonic 0.11.0", - "tonic-build 0.9.2", + "tonic", + "tonic-build", ] [[package]] name = "dapi-grpc-macros" -version = "1.4.0-dev.3" +version = "1.4.1" dependencies = [ "dapi-grpc", "heck 0.5.0", @@ -1208,20 +1105,20 @@ dependencies = [ [[package]] name = "dash-sdk" -version = "1.4.0-dev.3" +version = "1.4.1" dependencies = [ "arc-swap", "async-trait", "base64 0.22.1", "bip37-bloom-filter", "chrono", - "ciborium", - "clap 4.5.16", + "ciborium 0.2.0", + "clap", "dapi-grpc", "dapi-grpc-macros", "dashcore-rpc", "data-contracts", - "derive_more", + "derive_more 1.0.0", "dotenvy", "dpp", "drive", @@ -1229,20 +1126,20 @@ dependencies = [ "envy", "futures", "hex", - "http 0.2.12", + "http", "lru", - "pollster", "rs-dapi-client", "sanitize-filename", "serde", "serde_json", - "test-case 3.3.1", + "test-case", "thiserror", "tokio", "tokio-test", "tokio-util", "tracing", "tracing-subscriber", + "zeroize", ] [[package]] @@ -1308,7 +1205,7 @@ dependencies = [ [[package]] name = "dashpay-contract" -version = "1.4.0-dev.3" +version = "1.4.1" dependencies = [ "platform-value", "platform-version", @@ -1318,7 +1215,7 @@ dependencies = [ [[package]] name = "data-contracts" -version = "1.4.0-dev.3" +version = "1.4.1" dependencies = [ "dashpay-contract", "dpns-contract", @@ -1333,13 +1230,13 @@ dependencies = [ [[package]] name = "delegate" -version = "0.9.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d358e0ec5c59a5e1603b933def447096886121660fc680dc1e64a0753981fe3c" +checksum = "5060bb0febb73fa907273f8a7ed17ab4bf831d585eac835b28ec24a1e2460956" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.75", ] [[package]] @@ -1387,16 +1284,31 @@ dependencies = [ ] [[package]] -name = "diff" -version = "0.1.13" +name = "derive_more" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" +checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" +dependencies = [ + "derive_more-impl", +] [[package]] -name = "difflib" -version = "0.4.0" +name = "derive_more-impl" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.75", + "unicode-xid", +] + +[[package]] +name = "diff" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" [[package]] name = "digest" @@ -1434,7 +1346,7 @@ checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" [[package]] name = "dpns-contract" -version = "1.4.0-dev.3" +version = "1.4.1" dependencies = [ "platform-value", "platform-version", @@ -1444,7 +1356,7 @@ dependencies = [ [[package]] name = "dpp" -version = "1.4.0-dev.3" +version = "1.4.1" dependencies = [ "anyhow", "assert_matches", @@ -1452,27 +1364,27 @@ dependencies = [ "base64 0.22.1", "bincode", "bls-signatures", - "bs58 0.4.0", + "bs58", "byteorder", "chrono", - "ciborium", + "ciborium 0.2.0", "dashcore", "data-contracts", - "derive_more", + "derive_more 1.0.0", "dpp", "ed25519-dalek", - "env_logger 0.9.3", + "env_logger 0.11.5", "getrandom", "hex", "indexmap 2.6.0", "integer-encoding", - "itertools 0.12.1", + "itertools 0.13.0", "json-schema-compatibility-validator", "jsonschema", "lazy_static", "log", "nohash-hasher", - "num_enum", + "num_enum 0.7.3", "once_cell", "platform-serialization", "platform-serialization-derive", @@ -1488,26 +1400,26 @@ dependencies = [ "serde_json", "serde_repr", "sha2", - "strum 0.25.0", - "test-case 2.2.2", + "strum", + "test-case", "thiserror", "tokio", ] [[package]] name = "drive" -version = "1.4.0-dev.3" +version = "1.4.1" dependencies = [ "arc-swap", "assert_matches", "base64 0.22.1", "bincode", - "bs58 0.5.1", + "bs58", "byteorder", "chrono", - "ciborium", + "ciborium 0.2.0", "criterion", - "derive_more", + "derive_more 1.0.0", "dpp", "enum-map", "grovedb", @@ -1520,7 +1432,7 @@ dependencies = [ "indexmap 2.6.0", "integer-encoding", "intmap", - "itertools 0.11.0", + "itertools 0.13.0", "moka", "nohash-hasher", "once_cell", @@ -1537,23 +1449,22 @@ dependencies = [ [[package]] name = "drive-abci" -version = "1.4.0-dev.3" +version = "1.4.1" dependencies = [ "arc-swap", "assert_matches", "async-trait", - "atty", "base64 0.22.1", "bincode", - "bs58 0.5.1", + "bs58", "chrono", - "ciborium", - "clap 4.5.16", + "ciborium 0.2.0", + "clap", "console-subscriber", "dapi-grpc", "dashcore-rpc", "delegate", - "derive_more", + "derive_more 1.0.0", "dotenvy", "dpp", "drive", @@ -1563,13 +1474,13 @@ dependencies = [ "hex", "indexmap 2.6.0", "integer-encoding", - "itertools 0.10.5", + "itertools 0.13.0", "lazy_static", "metrics", "metrics-exporter-prometheus", "mockall", "platform-version", - "prost 0.12.6", + "prost", "rand", "regex", "reopen", @@ -1593,11 +1504,11 @@ dependencies = [ [[package]] name = "drive-proof-verifier" -version = "1.4.0-dev.3" +version = "1.4.1" dependencies = [ "bincode", "dapi-grpc", - "derive_more", + "derive_more 1.0.0", "dpp", "drive", "hex", @@ -1693,16 +1604,13 @@ dependencies = [ ] [[package]] -name = "env_logger" -version = "0.9.3" +name = "env_filter" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" +checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" dependencies = [ - "atty", - "humantime", "log", "regex", - "termcolor", ] [[package]] @@ -1718,6 +1626,19 @@ dependencies = [ "termcolor", ] +[[package]] +name = "env_logger" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", +] + [[package]] name = "envy" version = "0.4.2" @@ -1744,19 +1665,25 @@ dependencies = [ ] [[package]] -name = "error-chain" -version = "0.12.4" +name = "event-listener" +version = "5.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" dependencies = [ - "version_check", + "concurrent-queue", + "parking", + "pin-project-lite", ] [[package]] -name = "event-listener" -version = "2.5.3" +name = "event-listener-strategy" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" +checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" +dependencies = [ + "event-listener", + "pin-project-lite", +] [[package]] name = "failure" @@ -1791,15 +1718,6 @@ dependencies = [ "regex-syntax 0.8.4", ] -[[package]] -name = "fastrand" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] - [[package]] name = "fastrand" version = "2.1.0" @@ -1808,7 +1726,7 @@ checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" [[package]] name = "feature-flags-contract" -version = "1.4.0-dev.3" +version = "1.4.1" dependencies = [ "platform-value", "platform-version", @@ -1857,15 +1775,6 @@ dependencies = [ "paste", ] -[[package]] -name = "float-cmp" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" -dependencies = [ - "num-traits", -] - [[package]] name = "fnv" version = "1.0.7" @@ -1972,21 +1881,6 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" -[[package]] -name = "futures-lite" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" -dependencies = [ - "fastrand 1.9.0", - "futures-core", - "futures-io", - "memchr", - "parking", - "pin-project-lite", - "waker-fn", -] - [[package]] name = "futures-macro" version = "0.3.30" @@ -2063,17 +1957,29 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +[[package]] +name = "gloo-timers" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + [[package]] name = "grovedb" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d91e8f87926c834c7338d0c69a48816c043e0cddf0062a8a567483db2fb1e24" dependencies = [ - "axum 0.7.5", + "axum", "bincode", "bitvec", "blake3", - "derive_more", + "derive_more 0.99.18", "grovedb-costs", "grovedb-merk", "grovedb-path", @@ -2169,7 +2075,7 @@ dependencies = [ "lazy_static", "num_cpus", "rocksdb", - "strum 0.26.3", + "strum", "tempfile", "thiserror", ] @@ -2204,25 +2110,6 @@ dependencies = [ "serde_with 3.9.0", ] -[[package]] -name = "h2" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http 0.2.12", - "indexmap 2.6.0", - "slab", - "tokio", - "tokio-util", - "tracing", -] - [[package]] name = "h2" version = "0.4.6" @@ -2234,7 +2121,7 @@ dependencies = [ "fnv", "futures-core", "futures-sink", - "http 1.1.0", + "http", "indexmap 2.6.0", "slab", "tokio", @@ -2248,6 +2135,16 @@ version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" +[[package]] +name = "half" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -2298,15 +2195,6 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - [[package]] name = "hermit-abi" version = "0.3.9" @@ -2358,17 +2246,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "http" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - [[package]] name = "http" version = "1.1.0" @@ -2380,17 +2257,6 @@ dependencies = [ "itoa", ] -[[package]] -name = "http-body" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" -dependencies = [ - "bytes", - "http 0.2.12", - "pin-project-lite", -] - [[package]] name = "http-body" version = "1.0.1" @@ -2398,7 +2264,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.1.0", + "http", ] [[package]] @@ -2409,8 +2275,8 @@ checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", "futures-util", - "http 1.1.0", - "http-body 1.0.1", + "http", + "http-body", "pin-project-lite", ] @@ -2422,11 +2288,11 @@ checksum = "08a397c49fec283e3d6211adbe480be95aae5f304cfb923e9970e08956d5168a" [[package]] name = "http-serde" -version = "1.1.3" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f560b665ad9f1572cfcaf034f7fb84338a7ce945216d64a90fd81f046a3caee" +checksum = "0f056c8559e3757392c8d091e796416e4649d8e49e88b8d76df6c002f05027fd" dependencies = [ - "http 0.2.12", + "http", "serde", ] @@ -2448,30 +2314,6 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" -[[package]] -name = "hyper" -version = "0.14.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2 0.3.26", - "http 0.2.12", - "http-body 0.4.6", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2 0.5.7", - "tokio", - "tower-service", - "tracing", - "want", -] - [[package]] name = "hyper" version = "1.4.1" @@ -2481,9 +2323,9 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.6", - "http 1.1.0", - "http-body 1.0.1", + "h2", + "http", + "http-body", "httparse", "httpdate", "itoa", @@ -2500,26 +2342,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" dependencies = [ "futures-util", - "http 1.1.0", - "hyper 1.4.1", + "http", + "hyper", "hyper-util", - "rustls 0.23.12", + "rustls", "rustls-pki-types", "tokio", - "tokio-rustls 0.26.0", + "tokio-rustls", "tower-service", ] [[package]] name = "hyper-timeout" -version = "0.4.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" +checksum = "3203a961e5c83b6f5498933e78b6b263e208c197b63e9c6c53cc82ffd3f63793" dependencies = [ - "hyper 0.14.30", + "hyper", + "hyper-util", "pin-project-lite", "tokio", - "tokio-io-timeout", + "tower-service", ] [[package]] @@ -2530,7 +2373,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper 1.4.1", + "hyper", "hyper-util", "native-tls", "tokio", @@ -2547,11 +2390,11 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http 1.1.0", - "http-body 1.0.1", - "hyper 1.4.1", + "http", + "http-body", + "hyper", "pin-project-lite", - "socket2 0.5.7", + "socket2", "tokio", "tower", "tower-service", @@ -2628,15 +2471,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "instant" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" -dependencies = [ - "cfg-if", -] - [[package]] name = "integer-encoding" version = "4.0.2" @@ -2652,17 +2486,6 @@ dependencies = [ "serde", ] -[[package]] -name = "io-lifetimes" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" -dependencies = [ - "hermit-abi 0.3.9", - "libc", - "windows-sys 0.48.0", -] - [[package]] name = "ipnet" version = "2.9.0" @@ -2706,18 +2529,18 @@ dependencies = [ [[package]] name = "itertools" -version = "0.11.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" dependencies = [ "either", ] [[package]] name = "itertools" -version = "0.12.1" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ "either", ] @@ -2759,7 +2582,7 @@ dependencies = [ [[package]] name = "json-schema-compatibility-validator" -version = "1.4.0-dev.3" +version = "1.4.1" dependencies = [ "assert_matches", "json-patch", @@ -2868,12 +2691,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "linux-raw-sys" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" - [[package]] name = "linux-raw-sys" version = "0.4.14" @@ -2921,18 +2738,9 @@ dependencies = [ "libc", ] -[[package]] -name = "mach2" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709" -dependencies = [ - "libc", -] - [[package]] name = "masternode-reward-shares-contract" -version = "1.4.0-dev.3" +version = "1.4.1" dependencies = [ "platform-value", "platform-version", @@ -2963,9 +2771,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "metrics" -version = "0.22.3" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2be3cbd384d4e955b231c895ce10685e3d8260c5ccffae898c96c723b0772835" +checksum = "884adb57038347dfbaf2d5065887b6cf4312330dc8e94bc30a1a839bd79d3261" dependencies = [ "ahash 0.8.11", "portable-atomic", @@ -2973,20 +2781,19 @@ dependencies = [ [[package]] name = "metrics-exporter-prometheus" -version = "0.14.0" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d58e362dc7206e9456ddbcdbd53c71ba441020e62104703075a69151e38d85f" +checksum = "b4f0c8427b39666bf970460908b213ec09b3b350f20c0c2eabcbba51704a08e6" dependencies = [ "base64 0.22.1", "http-body-util", - "hyper 1.4.1", - "hyper-tls", + "hyper", "hyper-util", "indexmap 2.6.0", "ipnet", "metrics", "metrics-util", - "quanta 0.12.3", + "quanta", "thiserror", "tokio", "tracing", @@ -2994,16 +2801,16 @@ dependencies = [ [[package]] name = "metrics-util" -version = "0.16.3" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b07a5eb561b8cbc16be2d216faf7757f9baf3bfb94dbb0fae3df8387a5bb47f" +checksum = "4259040465c955f9f2f1a4a8a16dc46726169bca0f88e8fb2dbeced487c3e828" dependencies = [ "crossbeam-epoch", "crossbeam-utils", "hashbrown 0.14.5", "metrics", "num_cpus", - "quanta 0.12.3", + "quanta", "sketches-ddsketch", ] @@ -3061,14 +2868,13 @@ dependencies = [ [[package]] name = "mockall" -version = "0.11.4" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c84490118f2ee2d74570d114f3d0493cbf02790df303d2707606c3e14e07c96" +checksum = "d4c28b3fb6d753d28c20e826cd46ee611fda1cf3cde03a443a974043247c065a" dependencies = [ "cfg-if", "downcast", "fragile", - "lazy_static", "mockall_derive", "predicates", "predicates-tree", @@ -3076,34 +2882,33 @@ dependencies = [ [[package]] name = "mockall_derive" -version = "0.11.4" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ce75669015c4f47b289fd4d4f56e894e4c96003ffdf3ac51313126f94c6cbb" +checksum = "341014e7f530314e9a1fdbc7400b244efea7122662c96bfa248c31da5bfb2020" dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.75", ] [[package]] name = "moka" -version = "0.11.3" +version = "0.12.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa6e72583bf6830c956235bff0d5afec8cf2952f579ebad18ae7821a917d950f" +checksum = "32cf62eb4dd975d2dde76432fb1075c49e3ee2331cf36f1f8fd4b66550d32b6f" dependencies = [ - "async-io", "async-lock", + "async-trait", "crossbeam-channel", "crossbeam-epoch", "crossbeam-utils", + "event-listener", "futures-util", "once_cell", "parking_lot", - "quanta 0.11.1", + "quanta", "rustc_version", - "scheduled-thread-pool", - "skeptic", "smallvec", "tagptr", "thiserror", @@ -3111,12 +2916,6 @@ dependencies = [ "uuid", ] -[[package]] -name = "multimap" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" - [[package]] name = "multimap" version = "0.10.0" @@ -3162,12 +2961,6 @@ dependencies = [ "minimal-lexical", ] -[[package]] -name = "normalize-line-endings" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" - [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -3290,7 +3083,16 @@ version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" dependencies = [ - "num_enum_derive", + "num_enum_derive 0.5.11", +] + +[[package]] +name = "num_enum" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" +dependencies = [ + "num_enum_derive 0.7.3", ] [[package]] @@ -3305,6 +3107,18 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "num_enum_derive" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" +dependencies = [ + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "syn 2.0.75", +] + [[package]] name = "object" version = "0.36.3" @@ -3506,7 +3320,7 @@ checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "platform-serialization" -version = "1.4.0-dev.3" +version = "1.4.1" dependencies = [ "bincode", "platform-version", @@ -3514,22 +3328,22 @@ dependencies = [ [[package]] name = "platform-serialization-derive" -version = "1.4.0-dev.3" +version = "1.4.1" dependencies = [ "proc-macro2", "quote", "syn 2.0.75", - "virtue 0.0.14", + "virtue 0.0.17", ] [[package]] name = "platform-value" -version = "1.4.0-dev.3" +version = "1.4.1" dependencies = [ "base64 0.22.1", "bincode", - "bs58 0.5.1", - "ciborium", + "bs58", + "ciborium 0.2.0", "hex", "indexmap 2.6.0", "lazy_static", @@ -3545,7 +3359,7 @@ dependencies = [ [[package]] name = "platform-value-convertible" -version = "1.4.0-dev.3" +version = "1.4.1" dependencies = [ "quote", "syn 2.0.75", @@ -3553,7 +3367,7 @@ dependencies = [ [[package]] name = "platform-version" -version = "1.4.0-dev.3" +version = "1.4.1" dependencies = [ "bincode", "grovedb-version", @@ -3564,7 +3378,7 @@ dependencies = [ [[package]] name = "platform-versioning" -version = "1.4.0-dev.3" +version = "1.4.1" dependencies = [ "proc-macro2", "quote", @@ -3599,28 +3413,6 @@ dependencies = [ "plotters-backend", ] -[[package]] -name = "polling" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" -dependencies = [ - "autocfg", - "bitflags 1.3.2", - "cfg-if", - "concurrent-queue", - "libc", - "log", - "pin-project-lite", - "windows-sys 0.48.0", -] - -[[package]] -name = "pollster" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22686f4785f02a4fcc856d3b3bb19bf6c8160d103f7a99cc258bddd0251dc7f2" - [[package]] name = "portable-atomic" version = "1.7.0" @@ -3644,16 +3436,12 @@ dependencies = [ [[package]] name = "predicates" -version = "2.1.5" +version = "3.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59230a63c37f3e18569bdb90e4a89cbf5bf8b06fea0b84e65ea10cc4df47addd" +checksum = "7e9086cc7640c29a356d1a29fd134380bee9d8f79a17410aa76e7ad295f42c97" dependencies = [ - "difflib", - "float-cmp", - "itertools 0.10.5", - "normalize-line-endings", + "anstyle", "predicates-core", - "regex", ] [[package]] @@ -3682,16 +3470,6 @@ dependencies = [ "yansi", ] -[[package]] -name = "prettyplease" -version = "0.1.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" -dependencies = [ - "proc-macro2", - "syn 1.0.109", -] - [[package]] name = "prettyplease" version = "0.2.20" @@ -3730,7 +3508,6 @@ dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", - "syn 1.0.109", "version_check", ] @@ -3740,78 +3517,46 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - -[[package]] -name = "proc-macro2" -version = "1.0.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "prost" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" -dependencies = [ - "bytes", - "prost-derive 0.11.9", + "proc-macro2", + "quote", + "version_check", ] [[package]] -name = "prost" -version = "0.12.6" +name = "proc-macro2" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ - "bytes", - "prost-derive 0.12.6", + "unicode-ident", ] [[package]] -name = "prost-build" -version = "0.11.9" +name = "prost" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "119533552c9a7ffacc21e099c24a0ac8bb19c2a2a3f363de84cd9b844feab270" +checksum = "e13db3d3fde688c61e2446b4d843bc27a7e8af269a69440c0308021dc92333cc" dependencies = [ "bytes", - "heck 0.4.1", - "itertools 0.10.5", - "lazy_static", - "log", - "multimap 0.8.3", - "petgraph", - "prettyplease 0.1.25", - "prost 0.11.9", - "prost-types 0.11.9", - "regex", - "syn 1.0.109", - "tempfile", - "which", + "prost-derive", ] [[package]] name = "prost-build" -version = "0.12.6" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22505a5c94da8e3b7c2996394d1c933236c4d743e81a410bcca4e6989fc066a4" +checksum = "5bb182580f71dd070f88d01ce3de9f4da5021db7115d2e1c3605a754153b77c1" dependencies = [ "bytes", "heck 0.5.0", - "itertools 0.12.1", + "itertools 0.13.0", "log", - "multimap 0.10.0", + "multimap", "once_cell", "petgraph", - "prettyplease 0.2.20", - "prost 0.12.6", - "prost-types 0.12.6", + "prettyplease", + "prost", + "prost-types", "regex", "syn 2.0.75", "tempfile", @@ -3819,25 +3564,12 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" -dependencies = [ - "anyhow", - "itertools 0.10.5", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "prost-derive" -version = "0.12.6" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" +checksum = "18bec9b0adc4eba778b33684b7ba3e7137789434769ee3ce3930463ef904cfca" dependencies = [ "anyhow", - "itertools 0.12.1", + "itertools 0.13.0", "proc-macro2", "quote", "syn 2.0.75", @@ -3845,20 +3577,11 @@ dependencies = [ [[package]] name = "prost-types" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" -dependencies = [ - "prost 0.11.9", -] - -[[package]] -name = "prost-types" -version = "0.12.6" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9091c90b0a32608e984ff2fa4091273cbdd755d54935c51d520887f4a1dbd5b0" +checksum = "cee5168b05f49d4b0ca581206eb14a7b22fafd963efe729ac48eb03266e25cc2" dependencies = [ - "prost 0.12.6", + "prost", ] [[package]] @@ -3881,33 +3604,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "pulldown-cmark" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" -dependencies = [ - "bitflags 2.6.0", - "memchr", - "unicase", -] - -[[package]] -name = "quanta" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17e662a7a8291a865152364c20c7abc5e60486ab2001e8ec10b24862de0b9ab" -dependencies = [ - "crossbeam-utils", - "libc", - "mach2", - "once_cell", - "raw-cpuid 10.7.0", - "wasi", - "web-sys", - "winapi", -] - [[package]] name = "quanta" version = "0.12.3" @@ -3917,7 +3613,7 @@ dependencies = [ "crossbeam-utils", "libc", "once_cell", - "raw-cpuid 11.1.0", + "raw-cpuid", "wasi", "web-sys", "winapi", @@ -3968,15 +3664,6 @@ dependencies = [ "getrandom", ] -[[package]] -name = "raw-cpuid" -version = "10.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c297679cb867470fa8c9f67dbba74a78d78e3e98d7cf2b08d6d71540f797332" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "raw-cpuid" version = "11.1.0" @@ -4089,11 +3776,11 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2 0.4.6", - "http 1.1.0", - "http-body 1.0.1", + "h2", + "http", + "http-body", "http-body-util", - "hyper 1.4.1", + "hyper", "hyper-rustls", "hyper-tls", "hyper-util", @@ -4177,7 +3864,7 @@ dependencies = [ [[package]] name = "rs-dapi-client" -version = "1.4.0-dev.3" +version = "1.4.1" dependencies = [ "backon", "chrono", @@ -4253,20 +3940,6 @@ dependencies = [ "semver", ] -[[package]] -name = "rustix" -version = "0.37.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" -dependencies = [ - "bitflags 1.3.2", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys 0.3.8", - "windows-sys 0.48.0", -] - [[package]] name = "rustix" version = "0.38.34" @@ -4276,24 +3949,10 @@ dependencies = [ "bitflags 2.6.0", "errno", "libc", - "linux-raw-sys 0.4.14", + "linux-raw-sys", "windows-sys 0.52.0", ] -[[package]] -name = "rustls" -version = "0.22.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" -dependencies = [ - "log", - "ring", - "rustls-pki-types", - "rustls-webpki", - "subtle", - "zeroize", -] - [[package]] name = "rustls" version = "0.23.12" @@ -4311,9 +3970,9 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.7.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04182dffc9091a404e0fc069ea5cd60e5b866c3adf881eff99a32d048242dffa" +checksum = "fcaf18a4f2be7326cd874a5fa579fae794320a0f388d365dca7e480e55f83f8a" dependencies = [ "openssl-probe", "rustls-pemfile", @@ -4389,15 +4048,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "scheduled-thread-pool" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19" -dependencies = [ - "parking_lot", -] - [[package]] name = "scopeguard" version = "1.2.0" @@ -4459,9 +4109,6 @@ name = "semver" version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" -dependencies = [ - "serde", -] [[package]] name = "serde" @@ -4491,16 +4138,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_cbor" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" -dependencies = [ - "half", - "serde", -] - [[package]] name = "serde_derive" version = "1.0.208" @@ -4694,7 +4331,7 @@ checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" [[package]] name = "simple-signer" -version = "1.4.0-dev.3" +version = "1.4.1" dependencies = [ "base64 0.22.1", "bincode", @@ -4702,21 +4339,6 @@ dependencies = [ "dpp", ] -[[package]] -name = "skeptic" -version = "0.13.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16d23b015676c90a0f01c197bfdc786c20342c73a0afdda9025adb0bc42940a8" -dependencies = [ - "bytecount", - "cargo_metadata", - "error-chain", - "glob", - "pulldown-cmark", - "tempfile", - "walkdir", -] - [[package]] name = "sketches-ddsketch" version = "0.2.2" @@ -4738,16 +4360,6 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" -[[package]] -name = "socket2" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "socket2" version = "0.5.7" @@ -4785,7 +4397,7 @@ dependencies = [ [[package]] name = "strategy-tests" -version = "1.4.0-dev.3" +version = "1.4.1" dependencies = [ "bincode", "dpp", @@ -4808,35 +4420,13 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" -[[package]] -name = "strum" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" -dependencies = [ - "strum_macros 0.25.3", -] - [[package]] name = "strum" version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" dependencies = [ - "strum_macros 0.26.4", -] - -[[package]] -name = "strum_macros" -version = "0.25.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" -dependencies = [ - "heck 0.4.1", - "proc-macro2", - "quote", - "rustversion", - "syn 2.0.75", + "strum_macros", ] [[package]] @@ -4968,22 +4558,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" dependencies = [ "cfg-if", - "fastrand 2.1.0", + "fastrand", "once_cell", - "rustix 0.38.34", + "rustix", "windows-sys 0.59.0", ] [[package]] name = "tenderdash-abci" -version = "1.2.0+1.3.0" -source = "git+https://github.com/dashpay/rs-tenderdash-abci?tag=v1.2.0+1.3.0#79b1bcc141f8285fe9b5022f8288b4c49ddfbb0c" +version = "1.2.1+1.3.0" +source = "git+https://github.com/dashpay/rs-tenderdash-abci?tag=v1.2.1+1.3.0#aad72f4d25816bdf0f584ee4ba3cd383addf8a33" dependencies = [ "bytes", "futures", "hex", "lhash", - "prost 0.12.6", "semver", "serde_json", "tenderdash-proto", @@ -4998,33 +4587,33 @@ dependencies = [ [[package]] name = "tenderdash-proto" -version = "1.2.0+1.3.0" -source = "git+https://github.com/dashpay/rs-tenderdash-abci?tag=v1.2.0+1.3.0#79b1bcc141f8285fe9b5022f8288b4c49ddfbb0c" +version = "1.2.1+1.3.0" +source = "git+https://github.com/dashpay/rs-tenderdash-abci?tag=v1.2.1+1.3.0#aad72f4d25816bdf0f584ee4ba3cd383addf8a33" dependencies = [ "bytes", "chrono", - "derive_more", + "derive_more 1.0.0", "flex-error", "num-derive", "num-traits", - "prost 0.12.6", + "prost", "serde", "subtle-encoding", "tenderdash-proto-compiler", "time", - "tonic 0.11.0", + "tonic", ] [[package]] name = "tenderdash-proto-compiler" -version = "1.2.0+1.3.0" -source = "git+https://github.com/dashpay/rs-tenderdash-abci?tag=v1.2.0+1.3.0#79b1bcc141f8285fe9b5022f8288b4c49ddfbb0c" +version = "1.2.1+1.3.0" +source = "git+https://github.com/dashpay/rs-tenderdash-abci?tag=v1.2.1+1.3.0#aad72f4d25816bdf0f584ee4ba3cd383addf8a33" dependencies = [ "fs_extra", - "prost-build 0.12.6", + "prost-build", "regex", "tempfile", - "tonic-build 0.11.0", + "tonic-build", "ureq", "walkdir", "zip 2.2.0", @@ -5045,22 +4634,13 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" -[[package]] -name = "test-case" -version = "2.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21d6cf5a7dffb3f9dceec8e6b8ca528d9bd71d36c9f074defb548ce161f598c0" -dependencies = [ - "test-case-macros 2.2.2", -] - [[package]] name = "test-case" version = "3.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb2550dd13afcd286853192af8601920d959b14c401fcece38071d53bf0768a8" dependencies = [ - "test-case-macros 3.3.1", + "test-case-macros", ] [[package]] @@ -5075,19 +4655,6 @@ dependencies = [ "syn 2.0.75", ] -[[package]] -name = "test-case-macros" -version = "2.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e45b7bf6e19353ddd832745c8fcf77a17a93171df7151187f26623f2b75b5b26" -dependencies = [ - "cfg-if", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "test-case-macros" version = "3.3.1" @@ -5100,15 +4667,6 @@ dependencies = [ "test-case-core", ] -[[package]] -name = "textwrap" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -dependencies = [ - "unicode-width", -] - [[package]] name = "thiserror" version = "1.0.64" @@ -5208,22 +4766,12 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.7", + "socket2", "tokio-macros", "tracing", "windows-sys 0.52.0", ] -[[package]] -name = "tokio-io-timeout" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" -dependencies = [ - "pin-project-lite", - "tokio", -] - [[package]] name = "tokio-macros" version = "2.4.0" @@ -5245,33 +4793,22 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-rustls" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" -dependencies = [ - "rustls 0.22.4", - "rustls-pki-types", - "tokio", -] - [[package]] name = "tokio-rustls" version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.12", + "rustls", "rustls-pki-types", "tokio", ] [[package]] name = "tokio-stream" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" dependencies = [ "futures-core", "pin-project-lite", @@ -5362,55 +4899,30 @@ dependencies = [ [[package]] name = "tonic" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d560933a0de61cf715926b9cac824d4c883c2c43142f787595e48280c40a1d0e" -dependencies = [ - "async-stream", - "async-trait", - "axum 0.6.20", - "base64 0.21.7", - "bytes", - "h2 0.3.26", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.30", - "hyper-timeout", - "percent-encoding", - "pin-project", - "prost 0.12.6", - "tokio", - "tokio-stream", - "tower", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tonic" -version = "0.11.0" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76c4eb7a4e9ef9d4763600161f12f5070b92a578e1b634db88a6887844c91a13" +checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52" dependencies = [ "async-stream", "async-trait", - "axum 0.6.20", - "base64 0.21.7", + "axum", + "base64 0.22.1", "bytes", - "h2 0.3.26", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.30", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", "hyper-timeout", + "hyper-util", "percent-encoding", "pin-project", - "prost 0.12.6", + "prost", "rustls-native-certs", "rustls-pemfile", - "rustls-pki-types", + "socket2", "tokio", - "tokio-rustls 0.25.0", + "tokio-rustls", "tokio-stream", "tower", "tower-layer", @@ -5421,26 +4933,13 @@ dependencies = [ [[package]] name = "tonic-build" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6fdaae4c2c638bb70fe42803a26fbd6fc6ac8c72f5c59f67ecc2a2dcabf4b07" -dependencies = [ - "prettyplease 0.1.25", - "proc-macro2", - "prost-build 0.11.9", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "tonic-build" -version = "0.11.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4ef6dd70a610078cb4e338a0f79d06bc759ff1b22d2120c2ff02ae264ba9c2" +checksum = "568392c5a2bd0020723e3f387891176aabafe36fd9fcd074ad309dfa0c8eb964" dependencies = [ - "prettyplease 0.2.20", + "prettyplease", "proc-macro2", - "prost-build 0.12.6", + "prost-build", "quote", "syn 2.0.75", ] @@ -5473,8 +4972,8 @@ dependencies = [ "bitflags 2.6.0", "bytes", "futures-util", - "http 1.1.0", - "http-body 1.0.1", + "http", + "http-body", "http-body-util", "http-range-header", "httpdate", @@ -5582,9 +5081,9 @@ checksum = "e2ce481b2b7c2534fe7b5242cccebf37f9084392665c6a3783c414a1bada5432" [[package]] name = "triomphe" -version = "0.1.13" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6631e42e10b40c0690bf92f404ebcfe6e1fdb480391d15f17cc8e96eeed5369" +checksum = "859eb650cfee7434994602c3a68b25d77ad9e68c8a6cd491616ef86661382eb3" [[package]] name = "try-lock" @@ -5628,12 +5127,6 @@ dependencies = [ "tinyvec", ] -[[package]] -name = "unicode-width" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" - [[package]] name = "unicode-xid" version = "0.2.5" @@ -5656,7 +5149,7 @@ dependencies = [ "flate2", "log", "once_cell", - "rustls 0.23.12", + "rustls", "rustls-pki-types", "url", "webpki-roots", @@ -5726,15 +5219,9 @@ checksum = "9dcc60c0624df774c82a0ef104151231d37da4962957d691c011c852b2473314" [[package]] name = "virtue" -version = "0.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b522f715ead3537dc57c9907899a08e461a8f1e87fc8414a4a89bbd9854289ff" - -[[package]] -name = "waker-fn" -version = "1.2.0" +version = "0.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" +checksum = "7302ac74a033bf17b6e609ceec0f891ca9200d502d31f02dc7908d3d98767c9d" [[package]] name = "walkdir" @@ -5829,17 +5316,17 @@ checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93" [[package]] name = "wasm-dpp" -version = "1.4.0-dev.3" +version = "1.4.1" dependencies = [ "anyhow", "async-trait", "bincode", "dpp", "hex", - "itertools 0.10.5", + "itertools 0.13.0", "js-sys", "log", - "num_enum", + "num_enum 0.7.3", "paste", "serde", "serde-wasm-bindgen", @@ -5890,7 +5377,7 @@ dependencies = [ "either", "home", "once_cell", - "rustix 0.38.34", + "rustix", ] [[package]] @@ -6131,9 +5618,9 @@ dependencies = [ [[package]] name = "withdrawals-contract" -version = "1.4.0-dev.3" +version = "1.4.1" dependencies = [ - "num_enum", + "num_enum 0.5.11", "platform-value", "platform-version", "serde", @@ -6183,6 +5670,21 @@ name = "zeroize" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +dependencies = [ + "serde", + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.75", +] [[package]] name = "zip" diff --git a/Dockerfile b/Dockerfile index a96488115b..5039a062b6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -30,7 +30,7 @@ # SCCACHE_SERVER_PORT port to avoid conflicts in case of parallel compilation ARG ALPINE_VERSION=3.18 -ARG PROTOC_VERSION=25.2 +ARG PROTOC_VERSION=27.3 ARG RUSTC_WRAPPER # diff --git a/README.md b/README.md index fd688fbc88..3b2bd65ecb 100644 --- a/README.md +++ b/README.md @@ -25,8 +25,6 @@ If you are looking for how to contribute to the project or need any help with building an app on the Dash Platform - message us on the [Devs Discord](https://chat.dashdevs.org/)! -## Note: Dash Platform is currently available on the Dash Testnet only - ## Intro This is a multi-package repository - sometimes also known as monorepository - @@ -41,9 +39,9 @@ Dash Platform is currently undergoing testing and final development necessary to support its release on the Dash production network (mainnet). The packages in this repository may be used on the following networks: -- [x] **Development networks** ([**devnets**](https://dashplatform.readme.io/docs/reference-glossary#devnet)) -- [x] [**Testnet**](https://dashplatform.readme.io/docs/reference-glossary#testnet) -- [x] [Mainnet](https://dashplatform.readme.io/docs/reference-glossary#mainnet) +- [x] **Development networks** ([**devnets**](https://docs.dash.org/projects/platform/en/stable/docs/reference/glossary.html#devnet)) +- [x] [**Testnet**](https://docs.dash.org/projects/platform/en/stable/docs/reference/glossary.html#testnet) +- [x] [Mainnet](https://docs.dash.org/projects/platform/en/stable/docs/reference/glossary.html#mainnet) ## FAQ @@ -54,7 +52,7 @@ this repository may be used on the following networks: - [node.js](https://nodejs.org/) v20 - [docker](https://docs.docker.com/get-docker/) v20.10+ - [rust](https://www.rust-lang.org/tools/install) v1.80+, with wasm32 target (`rustup target add wasm32-unknown-unknown`) - - [protoc - protobuf compiler](https://github.com/protocolbuffers/protobuf/releases) v25.2+ + - [protoc - protobuf compiler](https://github.com/protocolbuffers/protobuf/releases) v27.3+ - if needed, set PROTOC environment variable to location of `protoc` binary - [wasm-bingen toolchain](https://rustwasm.github.io/wasm-bindgen/): - **IMPORTANT (OSX only)**: built-in `llvm` on OSX does not work, needs to be installed from brew: @@ -89,7 +87,7 @@ Discord](https://chat.dashdevs.org/) ### Where are the docs? Our docs are hosted on -[readme.io](https://dashplatform.readme.io/docs/introduction-what-is-dash-platform). +[docs.dash.org](https://docs.dash.org/projects/platform/en/stable/docs/intro/what-is-dash-platform.html). You can create issues and feature requests in the [issues](https://github.com/dashpay/platform/issues) for this repository. diff --git a/package.json b/package.json index dffdebc4c6..c1a993ced1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@dashevo/platform", - "version": "1.4.0-dev.3", + "version": "1.4.1", "private": true, "scripts": { "setup": "yarn install && yarn run build && yarn run configure", @@ -91,7 +91,8 @@ "socks": "^2.8.1", "ws": "^8.17.1", "body-parser": "^1.20.3", - "path-to-regexp": "^1.9.0" + "path-to-regexp": "^1.9.0", + "cookie": "^0.7.0" }, "dependencies": { "node-gyp": "^10.0.1" diff --git a/packages/bench-suite/package.json b/packages/bench-suite/package.json index 3ff32b6958..1e6befe213 100644 --- a/packages/bench-suite/package.json +++ b/packages/bench-suite/package.json @@ -1,14 +1,14 @@ { "name": "@dashevo/bench-suite", "private": true, - "version": "1.4.0-dev.3", + "version": "1.4.1", "description": "Dash Platform benchmark tool", "scripts": { "bench": "node ./bin/bench.js", "lint": "" }, "dependencies": { - "@dashevo/dashcore-lib": "~0.21.3", + "@dashevo/dashcore-lib": "~0.22.0", "@dashevo/dpns-contract": "workspace:*", "@dashevo/wallet-lib": "workspace:*", "@dashevo/wasm-dpp": "workspace:*", diff --git a/packages/check-features/Cargo.toml b/packages/check-features/Cargo.toml index faeb5ec05f..de43293845 100644 --- a/packages/check-features/Cargo.toml +++ b/packages/check-features/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "check-features" -version = "1.4.0-dev.3" +version = "1.4.1" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/packages/dapi-grpc/Cargo.toml b/packages/dapi-grpc/Cargo.toml index 1511089d11..14aa3139be 100644 --- a/packages/dapi-grpc/Cargo.toml +++ b/packages/dapi-grpc/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "dapi-grpc" description = "GRPC client for Dash Platform" -version = "1.4.0-dev.3" +version = "1.4.1" authors = [ "Samuel Westrich ", "Igor Markin ", @@ -33,23 +33,23 @@ serde = ["dep:serde", "dep:serde_bytes"] mocks = ["serde", "dep:serde_json"] [dependencies] -prost = { version = "0.12.3" } +prost = { version = "0.13" } futures-core = "0.3.30" -tonic = { version = "0.11", features = [ +tonic = { version = "0.12", features = [ "codegen", "prost", ], default-features = false } serde = { version = "1.0.197", optional = true, features = ["derive"] } serde_bytes = { version = "0.11.12", optional = true } serde_json = { version = "1.0", optional = true } -tenderdash-proto = { git = "https://github.com/dashpay/rs-tenderdash-abci", version = "1.2.0+1.3.0", tag = "v1.2.0+1.3.0", default-features = false, features = [ +tenderdash-proto = { git = "https://github.com/dashpay/rs-tenderdash-abci", version = "1.2.1", tag = "v1.2.1+1.3.0", default-features = false, features = [ "grpc", ] } dapi-grpc-macros = { path = "../rs-dapi-grpc-macros" } platform-version = { path = "../rs-platform-version" } [build-dependencies] -tonic-build = { version = "0.9.2" } +tonic-build = { version = "0.12" } [lib] diff --git a/packages/dapi-grpc/package.json b/packages/dapi-grpc/package.json index 225c6f125e..2fd2bf508a 100644 --- a/packages/dapi-grpc/package.json +++ b/packages/dapi-grpc/package.json @@ -1,6 +1,6 @@ { "name": "@dashevo/dapi-grpc", - "version": "1.4.0-dev.3", + "version": "1.4.1", "description": "DAPI GRPC definition file and generated clients", "browser": "browser.js", "main": "node.js", diff --git a/packages/dapi/package.json b/packages/dapi/package.json index 1ecfc82b46..a6f52bdc50 100644 --- a/packages/dapi/package.json +++ b/packages/dapi/package.json @@ -1,7 +1,7 @@ { "name": "@dashevo/dapi", "private": true, - "version": "1.4.0-dev.3", + "version": "1.4.1", "description": "A decentralized API for the Dash network", "scripts": { "api": "node scripts/api.js", @@ -35,7 +35,7 @@ "dependencies": { "@dashevo/bls": "~1.2.9", "@dashevo/dapi-grpc": "workspace:*", - "@dashevo/dashcore-lib": "~0.21.3", + "@dashevo/dashcore-lib": "~0.22.0", "@dashevo/dashd-rpc": "^19.0.0", "@dashevo/grpc-common": "workspace:*", "@dashevo/wasm-dpp": "workspace:*", diff --git a/packages/dash-spv/package.json b/packages/dash-spv/package.json index c7892682c2..de71743fa0 100644 --- a/packages/dash-spv/package.json +++ b/packages/dash-spv/package.json @@ -1,6 +1,6 @@ { "name": "@dashevo/dash-spv", - "version": "2.4.0-dev.3", + "version": "2.4.1", "description": "Repository containing SPV functions used by @dashevo", "main": "index.js", "scripts": { @@ -14,7 +14,7 @@ "dependencies": { "@dashevo/dark-gravity-wave": "^1.1.1", "@dashevo/dash-util": "^2.0.3", - "@dashevo/dashcore-lib": "~0.21.3", + "@dashevo/dashcore-lib": "~0.22.0", "levelup": "^4.4.0", "memdown": "^5.1.0", "wasm-x11-hash": "~0.0.2" diff --git a/packages/dashmate/configs/defaults/getBaseConfigFactory.js b/packages/dashmate/configs/defaults/getBaseConfigFactory.js index f1e9237ba9..e26e67ca50 100644 --- a/packages/dashmate/configs/defaults/getBaseConfigFactory.js +++ b/packages/dashmate/configs/defaults/getBaseConfigFactory.js @@ -11,7 +11,6 @@ import { const { version } = JSON.parse(fs.readFileSync(path.join(PACKAGE_ROOT_DIR, 'package.json'), 'utf8')); /** - * @param {HomeDir} homeDir * @returns {getBaseConfig} */ export default function getBaseConfigFactory() { @@ -398,9 +397,6 @@ export default function getBaseConfigFactory() { validator: { pub_key_types: ['bls12381'], }, - version: { - app_version: '1', - }, timeout: { propose: '50000000000', propose_delta: '5000000000', diff --git a/packages/dashmate/configs/defaults/getMainnetConfigFactory.js b/packages/dashmate/configs/defaults/getMainnetConfigFactory.js index 0f83c4a7a1..0159941d2f 100644 --- a/packages/dashmate/configs/defaults/getMainnetConfigFactory.js +++ b/packages/dashmate/configs/defaults/getMainnetConfigFactory.js @@ -66,6 +66,11 @@ export default function getMainnetConfigFactory(homeDir, getBaseConfig) { genesis: { chain_id: 'evo1', validator_quorum_type: 4, + consensus_params: { + version: { + app_version: '1', + }, + }, }, }, abci: { diff --git a/packages/dashmate/configs/defaults/getTestnetConfigFactory.js b/packages/dashmate/configs/defaults/getTestnetConfigFactory.js index a8aec0152b..3558c1daa4 100644 --- a/packages/dashmate/configs/defaults/getTestnetConfigFactory.js +++ b/packages/dashmate/configs/defaults/getTestnetConfigFactory.js @@ -110,6 +110,11 @@ export default function getTestnetConfigFactory(homeDir, getBaseConfig) { genesis: { chain_id: 'dash-testnet-51', validator_quorum_type: 6, + consensus_params: { + version: { + app_version: '1', + }, + }, }, }, }, diff --git a/packages/dashmate/configs/getConfigFileMigrationsFactory.js b/packages/dashmate/configs/getConfigFileMigrationsFactory.js index 4b04f1376e..2620636325 100644 --- a/packages/dashmate/configs/getConfigFileMigrationsFactory.js +++ b/packages/dashmate/configs/getConfigFileMigrationsFactory.js @@ -448,12 +448,63 @@ export default function getConfigFileMigrationsFactory(homeDir, defaultConfigs) return configFile; }, '1.0.0-dev.2': (configFile) => { + const consensusParams = { + block: { + max_bytes: '2097152', + max_gas: '57631392000', + time_iota_ms: '5000', + }, + evidence: { + max_age: '100000', + max_age_num_blocks: '100000', + max_age_duration: '172800000000000', + }, + validator: { + pub_key_types: ['bls12381'], + }, + timeout: { + propose: '50000000000', + propose_delta: '5000000000', + vote: '10000000000', + vote_delta: '1000000000', + }, + synchrony: { + message_delay: '70000000000', + precision: '1000000000', + }, + abci: { + recheck_tx: true, + }, + version: { + app_version: '1', + }, + }; + + const genesis = { + base: { + consensus_params: lodash.cloneDeep(consensusParams), + }, + local: { + consensus_params: lodash.cloneDeep(consensusParams), + }, + testnet: { + chain_id: 'dash-testnet-51', + validator_quorum_type: 6, + consensus_params: lodash.cloneDeep(consensusParams), + }, + mainnet: { + chain_id: 'evo1', + validator_quorum_type: 4, + consensus_params: lodash.cloneDeep(consensusParams), + }, + }; + Object.entries(configFile.configs) .forEach(([name, options]) => { - if (defaultConfigs.has(name)) { - options.platform.drive.tenderdash.genesis = defaultConfigs.get(name) - .get('platform.drive.tenderdash.genesis'); + if (genesis[name]) { + options.platform.drive.tenderdash.genesis = genesis[name]; } + options.platform.dapi.api.docker.deploy = base.get('platform.dapi.api.docker.deploy'); let baseConfigName = name; @@ -774,6 +825,38 @@ export default function getConfigFileMigrationsFactory(homeDir, defaultConfigs) return configFile; }, '1.1.0-dev.1': (configFile) => { + const consensusParams = { + block: { + max_bytes: '2097152', + max_gas: '57631392000', + time_iota_ms: '5000', + }, + evidence: { + max_age: '100000', + max_age_num_blocks: '100000', + max_age_duration: '172800000000000', + }, + validator: { + pub_key_types: ['bls12381'], + }, + timeout: { + propose: '50000000000', + propose_delta: '5000000000', + vote: '10000000000', + vote_delta: '1000000000', + }, + synchrony: { + message_delay: '70000000000', + precision: '1000000000', + }, + abci: { + recheck_tx: true, + }, + version: { + app_version: '1', + }, + }; + Object.entries(configFile.configs) .forEach(([name, options]) => { if (name === 'local') { @@ -792,8 +875,12 @@ export default function getConfigFileMigrationsFactory(homeDir, defaultConfigs) options.platform.drive.tenderdash.p2p.maxConnections = 64; options.platform.drive.tenderdash.p2p.maxOutgoingConnections = 30; - options.platform.drive.tenderdash.genesis - .consensus_params = base.get('platform.drive.tenderdash.genesis.consensus_params'); + + if (defaultConfigs.has(name)) { + options.platform.drive.tenderdash.genesis + .consensus_params = lodash.cloneDeep(consensusParams); + } + options.platform.drive.tenderdash.docker.image = base.get('platform.drive.tenderdash.docker.image'); }); return configFile; @@ -911,6 +998,27 @@ export default function getConfigFileMigrationsFactory(homeDir, defaultConfigs) }); return configFile; }, + '1.4.0-dev.4': (configFile) => { + Object.entries(configFile.configs) + .forEach(([name, options]) => { + if (name === 'base' || name === 'local') { + delete options.platform.drive.tenderdash.genesis.consensus_params.version; + } else if (options.network === NETWORK_TESTNET) { + options.platform.drive.tenderdash.genesis.consensus_params.version = { + app_version: '1', + }; + } + }); + return configFile; + }, + '1.4.0': (configFile) => { + Object.entries(configFile.configs) + .forEach(([, options]) => { + options.platform.drive.abci.docker.image = 'dashpay/drive:1'; + options.platform.dapi.api.docker.image = 'dashpay/dapi:1'; + }); + return configFile; + }, }; } diff --git a/packages/dashmate/package.json b/packages/dashmate/package.json index fcb1fcbcdf..6620a2fc3f 100644 --- a/packages/dashmate/package.json +++ b/packages/dashmate/package.json @@ -1,6 +1,6 @@ { "name": "dashmate", - "version": "1.4.0-dev.3", + "version": "1.4.1", "description": "Distribution package for Dash node installation", "scripts": { "lint": "eslint .", @@ -56,7 +56,7 @@ "dependencies": { "@dashevo/bls": "~1.2.9", "@dashevo/dapi-client": "workspace:*", - "@dashevo/dashcore-lib": "~0.21.3", + "@dashevo/dashcore-lib": "~0.22.0", "@dashevo/dashd-rpc": "^19.0.0", "@dashevo/docker-compose": "^0.24.4", "@dashevo/wallet-lib": "workspace:*", diff --git a/packages/dashpay-contract/Cargo.toml b/packages/dashpay-contract/Cargo.toml index a1aec28ce4..35a591d48c 100644 --- a/packages/dashpay-contract/Cargo.toml +++ b/packages/dashpay-contract/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "dashpay-contract" description = "DashPay data contract schema and tools" -version = "1.4.0-dev.3" +version = "1.4.1" edition = "2021" rust-version.workspace = true license = "MIT" diff --git a/packages/dashpay-contract/package.json b/packages/dashpay-contract/package.json index 144a37446f..74bdc33f77 100644 --- a/packages/dashpay-contract/package.json +++ b/packages/dashpay-contract/package.json @@ -1,6 +1,6 @@ { "name": "@dashevo/dashpay-contract", - "version": "1.4.0-dev.3", + "version": "1.4.1", "description": "Reference contract of the DashPay DPA on Dash Evolution", "scripts": { "lint": "eslint .", diff --git a/packages/data-contracts/Cargo.toml b/packages/data-contracts/Cargo.toml index fb604b07ad..21b309f881 100644 --- a/packages/data-contracts/Cargo.toml +++ b/packages/data-contracts/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "data-contracts" description = "Dash Platform system data contracts" -version = "1.4.0-dev.3" +version = "1.4.1" edition = "2021" rust-version.workspace = true license = "MIT" diff --git a/packages/dpns-contract/Cargo.toml b/packages/dpns-contract/Cargo.toml index f9254361eb..0841354e40 100644 --- a/packages/dpns-contract/Cargo.toml +++ b/packages/dpns-contract/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "dpns-contract" description = "DPNS data contract schema and tools" -version = "1.4.0-dev.3" +version = "1.4.1" edition = "2021" rust-version.workspace = true license = "MIT" diff --git a/packages/dpns-contract/package.json b/packages/dpns-contract/package.json index 875be96f51..98701984c1 100644 --- a/packages/dpns-contract/package.json +++ b/packages/dpns-contract/package.json @@ -1,6 +1,6 @@ { "name": "@dashevo/dpns-contract", - "version": "1.4.0-dev.3", + "version": "1.4.1", "description": "A contract and helper scripts for DPNS DApp", "scripts": { "lint": "eslint .", diff --git a/packages/feature-flags-contract/Cargo.toml b/packages/feature-flags-contract/Cargo.toml index 279ee40006..0a52c83f22 100644 --- a/packages/feature-flags-contract/Cargo.toml +++ b/packages/feature-flags-contract/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "feature-flags-contract" description = "Feature flags data contract schema and tools" -version = "1.4.0-dev.3" +version = "1.4.1" edition = "2021" rust-version.workspace = true license = "MIT" diff --git a/packages/feature-flags-contract/package.json b/packages/feature-flags-contract/package.json index 1bf9d4db4c..2c46c68e82 100644 --- a/packages/feature-flags-contract/package.json +++ b/packages/feature-flags-contract/package.json @@ -1,6 +1,6 @@ { "name": "@dashevo/feature-flags-contract", - "version": "1.4.0-dev.3", + "version": "1.4.1", "description": "Data Contract to store Dash Platform feature flags", "scripts": { "build": "", diff --git a/packages/js-dapi-client/package.json b/packages/js-dapi-client/package.json index ca913054b6..a3d72af982 100644 --- a/packages/js-dapi-client/package.json +++ b/packages/js-dapi-client/package.json @@ -1,6 +1,6 @@ { "name": "@dashevo/dapi-client", - "version": "1.4.0-dev.3", + "version": "1.4.1", "description": "Client library used to access Dash DAPI endpoints", "main": "lib/index.js", "contributors": [ @@ -28,7 +28,7 @@ "dependencies": { "@dashevo/dapi-grpc": "workspace:*", "@dashevo/dash-spv": "workspace:*", - "@dashevo/dashcore-lib": "~0.21.3", + "@dashevo/dashcore-lib": "~0.22.0", "@dashevo/grpc-common": "workspace:*", "@dashevo/wasm-dpp": "workspace:*", "bs58": "^4.0.1", diff --git a/packages/js-dash-sdk/package.json b/packages/js-dash-sdk/package.json index e398d330b9..5f232ba903 100644 --- a/packages/js-dash-sdk/package.json +++ b/packages/js-dash-sdk/package.json @@ -1,6 +1,6 @@ { "name": "dash", - "version": "4.4.0-dev.3", + "version": "4.4.1", "description": "Dash library for JavaScript/TypeScript ecosystem (Wallet, DAPI, Primitives, BLS, ...)", "main": "build/index.js", "unpkg": "dist/dash.min.js", @@ -41,7 +41,7 @@ "@dashevo/bls": "~1.2.9", "@dashevo/dapi-client": "workspace:*", "@dashevo/dapi-grpc": "workspace:*", - "@dashevo/dashcore-lib": "~0.21.3", + "@dashevo/dashcore-lib": "~0.22.0", "@dashevo/dashpay-contract": "workspace:*", "@dashevo/dpns-contract": "workspace:*", "@dashevo/grpc-common": "workspace:*", diff --git a/packages/js-dash-sdk/src/SDK/Client/Platform/methods/identities/creditWithdrawal.ts b/packages/js-dash-sdk/src/SDK/Client/Platform/methods/identities/creditWithdrawal.ts index 4be23a4a67..359c569b4b 100644 --- a/packages/js-dash-sdk/src/SDK/Client/Platform/methods/identities/creditWithdrawal.ts +++ b/packages/js-dash-sdk/src/SDK/Client/Platform/methods/identities/creditWithdrawal.ts @@ -49,8 +49,8 @@ export async function creditWithdrawal( // eslint-disable-next-line no-param-reassign options = { - ...options, signingKeyIndex: 3, + ...options, }; const { dpp } = this; diff --git a/packages/js-grpc-common/package.json b/packages/js-grpc-common/package.json index bd5df0bf4b..ee51714414 100644 --- a/packages/js-grpc-common/package.json +++ b/packages/js-grpc-common/package.json @@ -1,6 +1,6 @@ { "name": "@dashevo/grpc-common", - "version": "1.4.0-dev.3", + "version": "1.4.1", "description": "Common GRPC library", "main": "index.js", "scripts": { diff --git a/packages/masternode-reward-shares-contract/Cargo.toml b/packages/masternode-reward-shares-contract/Cargo.toml index e132fdd28c..e7b8c4a298 100644 --- a/packages/masternode-reward-shares-contract/Cargo.toml +++ b/packages/masternode-reward-shares-contract/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "masternode-reward-shares-contract" description = "Masternode reward shares data contract schema and tools" -version = "1.4.0-dev.3" +version = "1.4.1" edition = "2021" rust-version.workspace = true license = "MIT" diff --git a/packages/masternode-reward-shares-contract/package.json b/packages/masternode-reward-shares-contract/package.json index c94ad2ae59..8682f46915 100644 --- a/packages/masternode-reward-shares-contract/package.json +++ b/packages/masternode-reward-shares-contract/package.json @@ -1,6 +1,6 @@ { "name": "@dashevo/masternode-reward-shares-contract", - "version": "1.4.0-dev.3", + "version": "1.4.1", "description": "A contract and helper scripts for reward sharing", "scripts": { "lint": "eslint .", diff --git a/packages/platform-test-suite/package.json b/packages/platform-test-suite/package.json index bec32455d1..8655c8deac 100644 --- a/packages/platform-test-suite/package.json +++ b/packages/platform-test-suite/package.json @@ -1,7 +1,7 @@ { "name": "@dashevo/platform-test-suite", "private": true, - "version": "1.4.0-dev.3", + "version": "1.4.1", "description": "Dash Network end-to-end tests", "scripts": { "test": "yarn exec bin/test.sh", @@ -24,7 +24,7 @@ "homepage": "https://github.com/dashevo/platform-test-suite#readme", "dependencies": { "@dashevo/dapi-client": "workspace:*", - "@dashevo/dashcore-lib": "~0.21.3", + "@dashevo/dashcore-lib": "~0.22.0", "@dashevo/dpns-contract": "workspace:*", "@dashevo/feature-flags-contract": "workspace:*", "@dashevo/grpc-common": "workspace:*", diff --git a/packages/platform-test-suite/test/e2e/withdrawals.spec.js b/packages/platform-test-suite/test/e2e/withdrawals.spec.js index ecbac9b8de..f2a80ee433 100644 --- a/packages/platform-test-suite/test/e2e/withdrawals.spec.js +++ b/packages/platform-test-suite/test/e2e/withdrawals.spec.js @@ -8,7 +8,7 @@ const waitForSTPropagated = require('../../lib/waitForSTPropagated'); // TODO: temporary disabled due to flakiness. These tests aren't important for now, since we are // going to release v1.0.0 with withdrawals disabled. -describe.skip('Withdrawals', function withdrawalsTest() { +describe('Withdrawals', function withdrawalsTest() { this.bail(true); let client; @@ -38,7 +38,7 @@ describe.skip('Withdrawals', function withdrawalsTest() { }); describe('Any Identity', () => { - const INITIAL_BALANCE = 1000000; + const INITIAL_BALANCE = 2000000; before(async () => { identity = await client.platform.identities.register(INITIAL_BALANCE); @@ -57,7 +57,9 @@ describe.skip('Withdrawals', function withdrawalsTest() { await client.platform.identities.withdrawCredits( identity, BigInt(amountToWithdraw), - withdrawTo.address, + { + toAddress: withdrawTo.address, + }, ); // Re-fetch identity to obtain latest core chain lock height @@ -125,7 +127,9 @@ describe.skip('Withdrawals', function withdrawalsTest() { const { height: withdrawalHeight } = await client.platform.identities.withdrawCredits( identity, BigInt(amountToWithdraw), - withdrawTo.address, + { + toAddress: withdrawTo.address, + }, ); let withdrawalBroadcasted = false; @@ -173,11 +177,13 @@ describe.skip('Withdrawals', function withdrawalsTest() { await expect(client.platform.identities.withdrawCredits( identity, BigInt(amountToWithdraw), - withdrawTo.address, + { + toAddress: withdrawTo.address, + }, )).to.be.rejectedWith(`Withdrawal amount "${amountToWithdraw}" is bigger that identity balance "${identityBalanceBefore}"`); }); - it('should not allow to create withdrawal with wrong security key type', async () => { + it('should not allow to create withdrawal with authentication key purpose', async () => { const account = await client.getWalletAccount(); const identityBalanceBefore = identity.getBalance(); const withdrawTo = await account.getUnusedAddress(); @@ -186,11 +192,11 @@ describe.skip('Withdrawals', function withdrawalsTest() { await expect(client.platform.identities.withdrawCredits( identity, BigInt(amountToWithdraw), - withdrawTo.address, { + toAddress: withdrawTo.address, signingKeyIndex: 1, }, - )).to.be.rejectedWith('Error conversion not implemented: Invalid public key security level HIGH. The state transition requires one of CRITICAL'); + )).to.be.rejectedWith('Error conversion not implemented: Invalid identity key purpose AUTHENTICATION. This state transition requires TRANSFER | OWNER'); }); // TODO: Figure out how to overcome client-side validation and implement @@ -227,7 +233,9 @@ describe.skip('Withdrawals', function withdrawalsTest() { await client.platform.identities.withdrawCredits( identity, BigInt(1000000), - withdrawTo.address, + { + toAddress: withdrawTo.address, + }, ); await waitForSTPropagated(); diff --git a/packages/rs-dapi-client/Cargo.toml b/packages/rs-dapi-client/Cargo.toml index 0f78a7b792..f3682130fc 100644 --- a/packages/rs-dapi-client/Cargo.toml +++ b/packages/rs-dapi-client/Cargo.toml @@ -1,10 +1,11 @@ [package] name = "rs-dapi-client" -version = "1.4.0-dev.3" +version = "1.4.1" edition = "2021" [features] default = ["mocks", "offline-testing"] +tokio-sleep = ["backon/tokio-sleep"] mocks = [ "dep:sha2", "dep:hex", @@ -18,16 +19,19 @@ dump = ["mocks"] # skip tests that require connection to the platform; enabled by default offline-testing = [] - [dependencies] -backon = "0.4.1" -dapi-grpc = { path = "../dapi-grpc" } +backon = { version = "1.2"} +dapi-grpc = { path = "../dapi-grpc", features = [ + "core", + "platform", + "client", +], default-features = false } futures = "0.3.28" -http-serde = { version = "1.1.3", optional = true } +http-serde = { version = "2.1", optional = true } rand = { version = "0.8.5", features = ["small_rng"] } thiserror = "1.0.64" tracing = "0.1.40" -tokio = { version = "1.32.0", default-features = false } +tokio = { version = "1.40", default-features = false } sha2 = { version = "0.10", optional = true } hex = { version = "0.4.3", optional = true } lru = { version = "0.12.3" } @@ -35,4 +39,4 @@ serde = { version = "1.0.197", optional = true, features = ["derive"] } serde_json = { version = "1.0.120", optional = true } chrono = { version = "0.4.38", features = ["serde"] } [dev-dependencies] -tokio = { version = "1.32.0", features = ["macros"] } +tokio = { version = "1.40", features = ["macros"] } diff --git a/packages/rs-dapi-client/src/connection_pool.rs b/packages/rs-dapi-client/src/connection_pool.rs index 16d8cf030d..97dd991d50 100644 --- a/packages/rs-dapi-client/src/connection_pool.rs +++ b/packages/rs-dapi-client/src/connection_pool.rs @@ -67,19 +67,21 @@ impl ConnectionPool { /// * `prefix` - Prefix for the item in the pool. Used to distinguish between Core and Platform clients. /// * `uri` - URI of the node. /// * `settings` - Applied request settings. - pub fn get_or_create( + pub fn get_or_create( &self, prefix: PoolPrefix, uri: &Uri, settings: Option<&AppliedRequestSettings>, - create: impl FnOnce() -> PoolItem, - ) -> PoolItem { + create: impl FnOnce() -> Result, + ) -> Result { if let Some(cli) = self.get(prefix, uri, settings) { - return cli; + return Ok(cli); } let cli = create(); - self.put(uri, settings, cli.clone()); + if let Ok(cli) = &cli { + self.put(uri, settings, cli.clone()); + } cli } diff --git a/packages/rs-dapi-client/src/dapi_client.rs b/packages/rs-dapi-client/src/dapi_client.rs index 17748ab2b0..372b28bc3f 100644 --- a/packages/rs-dapi-client/src/dapi_client.rs +++ b/packages/rs-dapi-client/src/dapi_client.rs @@ -199,7 +199,13 @@ impl DapiRequestExecutor for DapiClient { address.uri().clone(), &applied_settings, &pool, - ); + ) + .map_err(|e| { + DapiClientError::<::Error>::Transport( + e, + address.clone(), + ) + })?; let response = transport_request .execute_transport(&mut transport_client, &applied_settings) @@ -250,7 +256,7 @@ impl DapiRequestExecutor for DapiClient { // Start the routine with retry policy applied: // We allow let_and_return because `result` is used later if dump feature is enabled let result = routine - .retry(&retry_settings) + .retry(retry_settings) .notify(|error, duration| { tracing::warn!( ?error, diff --git a/packages/rs-dapi-client/src/transport.rs b/packages/rs-dapi-client/src/transport.rs index a5459834e1..600189fc2f 100644 --- a/packages/rs-dapi-client/src/transport.rs +++ b/packages/rs-dapi-client/src/transport.rs @@ -51,12 +51,12 @@ pub trait TransportClient: Send + Sized { type Error: CanRetry + Send + Debug + Mockable; /// Build client using node's url. - fn with_uri(uri: Uri, pool: &ConnectionPool) -> Self; + fn with_uri(uri: Uri, pool: &ConnectionPool) -> Result; /// Build client using node's url and [AppliedRequestSettings]. fn with_uri_and_settings( uri: Uri, settings: &AppliedRequestSettings, pool: &ConnectionPool, - ) -> Self; + ) -> Result; } diff --git a/packages/rs-dapi-client/src/transport/grpc.rs b/packages/rs-dapi-client/src/transport/grpc.rs index 98976ed08e..d5180099d0 100644 --- a/packages/rs-dapi-client/src/transport/grpc.rs +++ b/packages/rs-dapi-client/src/transport/grpc.rs @@ -8,7 +8,7 @@ use crate::{request_settings::AppliedRequestSettings, RequestSettings}; use dapi_grpc::core::v0::core_client::CoreClient; use dapi_grpc::core::v0::{self as core_proto}; use dapi_grpc::platform::v0::{self as platform_proto, platform_client::PlatformClient}; -use dapi_grpc::tonic::transport::Uri; +use dapi_grpc::tonic::transport::{ClientTlsConfig, Uri}; use dapi_grpc::tonic::Streaming; use dapi_grpc::tonic::{transport::Channel, IntoRequest}; use futures::{future::BoxFuture, FutureExt, TryFutureExt}; @@ -18,8 +18,16 @@ pub type PlatformGrpcClient = PlatformClient; /// Core Client using gRPC transport. pub type CoreGrpcClient = CoreClient; -fn create_channel(uri: Uri, settings: Option<&AppliedRequestSettings>) -> Channel { - let mut builder = Channel::builder(uri); +fn create_channel( + uri: Uri, + settings: Option<&AppliedRequestSettings>, +) -> Result { + let mut builder = Channel::builder(uri).tls_config( + ClientTlsConfig::new() + .with_native_roots() + .with_webpki_roots() + .assume_http2(true), + )?; if let Some(settings) = settings { if let Some(timeout) = settings.connect_timeout { @@ -27,50 +35,84 @@ fn create_channel(uri: Uri, settings: Option<&AppliedRequestSettings>) -> Channe } } - builder.connect_lazy() + Ok(builder.connect_lazy()) } impl TransportClient for PlatformGrpcClient { type Error = dapi_grpc::tonic::Status; - fn with_uri(uri: Uri, pool: &ConnectionPool) -> Self { - pool.get_or_create(PoolPrefix::Platform, &uri, None, || { - Self::new(create_channel(uri.clone(), None)).into() - }) - .into() + fn with_uri(uri: Uri, pool: &ConnectionPool) -> Result { + Ok(pool + .get_or_create(PoolPrefix::Platform, &uri, None, || { + match create_channel(uri.clone(), None) { + Ok(channel) => Ok(Self::new(channel).into()), + Err(e) => Err(dapi_grpc::tonic::Status::failed_precondition(format!( + "Channel creation failed: {}", + e + ))), + } + })? + .into()) } fn with_uri_and_settings( uri: Uri, settings: &AppliedRequestSettings, pool: &ConnectionPool, - ) -> Self { - pool.get_or_create(PoolPrefix::Platform, &uri, Some(settings), || { - Self::new(create_channel(uri.clone(), Some(settings))).into() - }) - .into() + ) -> Result { + Ok(pool + .get_or_create( + PoolPrefix::Platform, + &uri, + Some(settings), + || match create_channel(uri.clone(), Some(settings)) { + Ok(channel) => Ok(Self::new(channel).into()), + Err(e) => Err(dapi_grpc::tonic::Status::failed_precondition(format!( + "Channel creation failed: {}", + e + ))), + }, + )? + .into()) } } impl TransportClient for CoreGrpcClient { type Error = dapi_grpc::tonic::Status; - fn with_uri(uri: Uri, pool: &ConnectionPool) -> Self { - pool.get_or_create(PoolPrefix::Core, &uri, None, || { - Self::new(create_channel(uri.clone(), None)).into() - }) - .into() + fn with_uri(uri: Uri, pool: &ConnectionPool) -> Result { + Ok(pool + .get_or_create(PoolPrefix::Core, &uri, None, || { + match create_channel(uri.clone(), None) { + Ok(channel) => Ok(Self::new(channel).into()), + Err(e) => Err(dapi_grpc::tonic::Status::failed_precondition(format!( + "Channel creation failed: {}", + e + ))), + } + })? + .into()) } fn with_uri_and_settings( uri: Uri, settings: &AppliedRequestSettings, pool: &ConnectionPool, - ) -> Self { - pool.get_or_create(PoolPrefix::Core, &uri, Some(settings), || { - Self::new(create_channel(uri.clone(), Some(settings))).into() - }) - .into() + ) -> Result { + Ok(pool + .get_or_create( + PoolPrefix::Core, + &uri, + Some(settings), + || match create_channel(uri.clone(), Some(settings)) { + Ok(channel) => Ok(Self::new(channel).into()), + Err(e) => Err(dapi_grpc::tonic::Status::failed_precondition(format!( + "Channel creation failed: {}", + e + ))), + }, + )? + .into()) } } diff --git a/packages/rs-dapi-grpc-macros/Cargo.toml b/packages/rs-dapi-grpc-macros/Cargo.toml index de3afc354d..8df0883193 100644 --- a/packages/rs-dapi-grpc-macros/Cargo.toml +++ b/packages/rs-dapi-grpc-macros/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "dapi-grpc-macros" -version = "1.4.0-dev.3" +version = "1.4.1" edition = "2021" description = "Macros used by dapi-grpc. Internal use only." @@ -9,8 +9,8 @@ description = "Macros used by dapi-grpc. Internal use only." proc-macro = true [dependencies] -quote = "1.0.33" -syn = "2.0.38" +quote = "1.0.37" +syn = "2.0.75" heck = "0.5.0" [dev-dependencies] diff --git a/packages/rs-dpp/Cargo.toml b/packages/rs-dpp/Cargo.toml index 47d8258550..4d7d1c79d9 100644 --- a/packages/rs-dpp/Cargo.toml +++ b/packages/rs-dpp/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dpp" -version = "1.4.0-dev.3" +version = "1.4.1" edition = "2021" rust-version.workspace = true authors = [ @@ -16,7 +16,7 @@ anyhow = { version = "1.0.81" } async-trait = { version = "0.1.79" } base64 = "0.22.1" bls-signatures = { git = "https://github.com/dashpay/bls-signatures", tag = "v1.3.1", optional = true } -bs58 = "0.4.0" +bs58 = "0.5" byteorder = { version = "1.4" } chrono = { version = "0.4.35", default-features = false, features = [ "wasmbind", @@ -30,19 +30,19 @@ dashcore = { git = "https://github.com/dashpay/rust-dashcore", features = [ "signer", "serde", ], default-features = false, branch = "master" } -env_logger = { version = "0.9" } +env_logger = { version = "0.11" } getrandom = { version = "0.2", features = ["js"] } hex = { version = "0.4" } integer-encoding = { version = "4.0.0" } -itertools = { version = "0.12.1" } +itertools = { version = "0.13" } jsonschema = { git = "https://github.com/dashpay/jsonschema-rs", branch = "configure_regexp", default-features = false, features = [ "draft202012", ], optional = true } lazy_static = { version = "1.4" } log = { version = "0.4.6" } -num_enum = "0.5.7" +num_enum = "0.7" bincode = { version = "2.0.0-rc.3", features = ["serde"] } -rand = { version = "0.8.4", features = ["small_rng"] } +rand = { version = "0.8.5", features = ["small_rng"] } regex = { version = "1.10.4" } serde = { version = "1.0.197", features = ["derive"] } serde_json = { version = "1.0", features = ["preserve_order"] } @@ -55,21 +55,19 @@ platform-version = { path = "../rs-platform-version" } platform-versioning = { path = "../rs-platform-versioning" } platform-serialization = { path = "../rs-platform-serialization" } platform-serialization-derive = { path = "../rs-platform-serialization-derive" } -derive_more = "0.99.17" -ed25519-dalek = { version = "2.0.0-rc.2", features = [ - "rand_core", -], optional = true } +derive_more = { version = "1.0", features = ["from", "display"] } +ed25519-dalek = { version = "2.1", features = ["rand_core"], optional = true } nohash-hasher = "0.2.0" rust_decimal = "1.29.1" rust_decimal_macros = "1.29.1" indexmap = { version = "2.0.2", features = ["serde"] } -strum = { version = "0.25.0", features = ["derive"] } +strum = { version = "0.26", features = ["derive"] } json-schema-compatibility-validator = { path = '../rs-json-schema-compatibility-validator' } once_cell = "1.19.0" [dev-dependencies] -test-case = { version = "2.0" } -tokio = { version = "1.17", features = ["full"] } +test-case = { version = "3.3" } +tokio = { version = "1.40", features = ["full"] } pretty_assertions = { version = "1.4.1" } dpp = { path = ".", features = ["all_features_without_client"] } assert_matches = "1.5.0" diff --git a/packages/rs-dpp/src/core_types/validator/v0/mod.rs b/packages/rs-dpp/src/core_types/validator/v0/mod.rs index d472b4a145..b427431a04 100644 --- a/packages/rs-dpp/src/core_types/validator/v0/mod.rs +++ b/packages/rs-dpp/src/core_types/validator/v0/mod.rs @@ -1,6 +1,5 @@ use dashcore::{ProTxHash, PubkeyHash}; -use std::fmt; -use std::fmt::{Debug, Display, Formatter}; +use std::fmt::{Debug, Formatter}; use crate::bls_signatures::PublicKey as BlsPublicKey; #[cfg(feature = "core-types-serde-conversion")] @@ -48,7 +47,8 @@ impl Encode for ValidatorV0 { // Encode each field in the order they appear in the struct // Encode ProTxHash - self.pro_tx_hash.to_byte_array().to_vec().encode(encoder)?; + let pro_tx_hash_bytes = self.pro_tx_hash.as_byte_array(); + pro_tx_hash_bytes.encode(encoder)?; // Encode Option match &self.public_key { @@ -65,7 +65,8 @@ impl Encode for ValidatorV0 { self.node_ip.encode(encoder)?; // Encode node_id - self.node_id.to_byte_array().to_vec().encode(encoder)?; + let node_id_bytes = self.node_id.as_byte_array(); + node_id_bytes.encode(encoder)?; // Encode core_port, platform_http_port, and platform_p2p_port as u16 self.core_port.encode(encoder)?; @@ -85,14 +86,14 @@ impl Decode for ValidatorV0 { // Decode each field in the same order as they were encoded // Decode ProTxHash - let pro_tx_hash_bytes = Vec::::decode(decoder)?; + let pro_tx_hash_bytes = <[u8; 32]>::decode(decoder)?; let pro_tx_hash = ProTxHash::from_slice(&pro_tx_hash_bytes) .map_err(|_| DecodeError::OtherString("Failed to decode ProTxHash".to_string()))?; // Decode Option let has_public_key = bool::decode(decoder)?; let public_key = if has_public_key { - let public_key_bytes = Vec::::decode(decoder)?; + let public_key_bytes = <[u8; 48]>::decode(decoder)?; Some(BlsPublicKey::from_bytes(&public_key_bytes).map_err(|_| { DecodeError::OtherString("Failed to decode BlsPublicKey".to_string()) })?) @@ -104,7 +105,7 @@ impl Decode for ValidatorV0 { let node_ip = String::decode(decoder)?; // Decode node_id - let node_id_bytes = Vec::::decode(decoder)?; + let node_id_bytes = <[u8; 20]>::decode(decoder)?; let node_id = PubkeyHash::from_slice(&node_id_bytes) .map_err(|_| DecodeError::OtherString("Failed to decode NodeId".to_string()))?; @@ -251,3 +252,45 @@ impl ValidatorV0Setters for ValidatorV0 { self.is_banned = is_banned; } } + +#[cfg(test)] +mod tests { + use super::*; + use bincode::config; + + #[test] + fn test_serialize_deserialize_validator_v0() { + // Sample data for testing + let pro_tx_hash = ProTxHash::from_slice(&[1; 32]).unwrap(); + let public_key = Some(BlsPublicKey::generate()); + let node_ip = "127.0.0.1".to_string(); + let node_id = PubkeyHash::from_slice(&[3; 20]).unwrap(); + let core_port = 9999; + let platform_http_port = 8888; + let platform_p2p_port = 7777; + let is_banned = false; + + // Create a ValidatorV0 instance + let validator = ValidatorV0 { + pro_tx_hash, + public_key, + node_ip, + node_id, + core_port, + platform_http_port, + platform_p2p_port, + is_banned, + }; + + // Serialize the ValidatorV0 instance + let encoded = bincode::encode_to_vec(&validator, config::standard()).unwrap(); + + // Deserialize the data back into a ValidatorV0 instance + let decoded: ValidatorV0 = bincode::decode_from_slice(&encoded, config::standard()) + .unwrap() + .0; + + // Verify that the deserialized instance matches the original instance + assert_eq!(validator, decoded); + } +} diff --git a/packages/rs-dpp/src/core_types/validator_set/v0/mod.rs b/packages/rs-dpp/src/core_types/validator_set/v0/mod.rs index 2cf167277b..dba9180e24 100644 --- a/packages/rs-dpp/src/core_types/validator_set/v0/mod.rs +++ b/packages/rs-dpp/src/core_types/validator_set/v0/mod.rs @@ -70,7 +70,7 @@ impl Display for ValidatorSetV0 { impl Encode for ValidatorSetV0 { fn encode(&self, encoder: &mut E) -> Result<(), EncodeError> { // Encode each field in the order they appear in the struct - let quorum_hash_bytes = self.quorum_hash.as_byte_array().to_vec(); + let quorum_hash_bytes = self.quorum_hash.as_byte_array(); quorum_hash_bytes.encode(encoder)?; self.quorum_index.encode(encoder)?; self.core_height.encode(encoder)?; @@ -85,7 +85,7 @@ impl Encode for ValidatorSetV0 { // Custom encoding for BlsPublicKey if needed // Assuming BlsPublicKey can be serialized to a byte slice - let public_key_bytes = self.threshold_public_key.to_bytes(); + let public_key_bytes = *self.threshold_public_key.to_bytes(); public_key_bytes.encode(encoder)?; Ok(()) @@ -95,8 +95,8 @@ impl Encode for ValidatorSetV0 { #[cfg(feature = "core-types-serialization")] impl Decode for ValidatorSetV0 { fn decode(decoder: &mut D) -> Result { - // Decode each field in the same order as they were encoded - let quorum_hash = Vec::::decode(decoder)?; + // Decode the quorum hash directly as a [u8; 32] array + let quorum_hash = <[u8; 32]>::decode(decoder)?; let quorum_index = Option::::decode(decoder)?; let core_height = u32::decode(decoder)?; @@ -114,17 +114,16 @@ impl Decode for ValidatorSetV0 { }) .collect::>()?; - // Custom decoding for BlsPublicKey if needed - // Assuming BlsPublicKey can be deserialized from a byte slice - let public_key_bytes = Vec::::decode(decoder)?; + // Decode the [u8; 48] directly + let mut public_key_bytes = [0u8; 48]; + let bytes = <[u8; 48]>::decode(decoder)?; + public_key_bytes.copy_from_slice(&bytes); let threshold_public_key = BlsPublicKey::from_bytes(&public_key_bytes).map_err(|_| { bincode::error::DecodeError::OtherString("Failed to decode BlsPublicKey".to_string()) })?; Ok(ValidatorSetV0 { - quorum_hash: QuorumHash::from_slice(&quorum_hash).map_err(|_| { - bincode::error::DecodeError::OtherString("Failed to decode QuorumHash".to_string()) - })?, + quorum_hash: QuorumHash::from_byte_array(quorum_hash), quorum_index, core_height, members, @@ -138,8 +137,8 @@ impl<'de> BorrowDecode<'de> for ValidatorSetV0 { fn borrow_decode(decoder: &mut D) -> Result { // Decode each field in the same order as they were encoded - // Decode quorum_hash as Vec - let quorum_hash = Vec::::decode(decoder)?; + // Decode the quorum hash directly as a [u8; 32] array + let quorum_hash = <[u8; 32]>::decode(decoder)?; // Decode quorum_index as Option let quorum_index = Option::::decode(decoder)?; // Decode core_height as u32 @@ -160,15 +159,17 @@ impl<'de> BorrowDecode<'de> for ValidatorSetV0 { .collect::>()?; // Custom decoding for BlsPublicKey if needed - let public_key_bytes = Vec::::decode(decoder)?; + let mut public_key_bytes = [0u8; 48]; + let bytes = <[u8; 48]>::decode(decoder)?; + public_key_bytes.copy_from_slice(&bytes); let threshold_public_key = BlsPublicKey::from_bytes(&public_key_bytes).map_err(|_| { - bincode::error::DecodeError::OtherString("Failed to decode BlsPublicKey".to_string()) + bincode::error::DecodeError::OtherString( + "Failed to decode BlsPublicKey in borrow decode".to_string(), + ) })?; Ok(ValidatorSetV0 { - quorum_hash: QuorumHash::from_slice(&quorum_hash).map_err(|_| { - bincode::error::DecodeError::OtherString("Failed to decode QuorumHash".to_string()) - })?, + quorum_hash: QuorumHash::from_byte_array(quorum_hash), quorum_index, core_height, members, @@ -278,3 +279,62 @@ impl ValidatorSetV0Setters for ValidatorSetV0 { self.threshold_public_key = threshold_public_key; } } + +#[cfg(test)] +mod tests { + use super::*; + use bincode::config; + use dashcore::PubkeyHash; + use std::collections::BTreeMap; + + #[test] + fn test_serialize_deserialize_validator_set_v0() { + // Sample data for testing + let quorum_hash = QuorumHash::from_slice(&[1; 32]).unwrap(); + let quorum_index = Some(42); + let core_height = 1000; + + // Create a sample ProTxHash and ValidatorV0 instance + let pro_tx_hash = ProTxHash::from_slice(&[2; 32]).unwrap(); + let public_key = Some(BlsPublicKey::generate()); + let node_ip = "192.168.1.1".to_string(); + let node_id = PubkeyHash::from_slice(&[4; 20]).unwrap(); + let validator = ValidatorV0 { + pro_tx_hash: pro_tx_hash.clone(), + public_key, + node_ip, + node_id, + core_port: 8080, + platform_http_port: 9090, + platform_p2p_port: 10010, + is_banned: false, + }; + + // Create a BTreeMap with one entry for the ValidatorSetV0 + let mut members = BTreeMap::new(); + members.insert(pro_tx_hash, validator); + + // Create a sample threshold public key + let threshold_public_key = BlsPublicKey::generate(); + + // Create the ValidatorSetV0 instance + let validator_set = ValidatorSetV0 { + quorum_hash, + quorum_index, + core_height, + members, + threshold_public_key, + }; + + // Serialize the ValidatorSetV0 instance + let encoded = bincode::encode_to_vec(&validator_set, config::standard()).unwrap(); + + // Deserialize the data back into a ValidatorSetV0 instance + let decoded: ValidatorSetV0 = bincode::decode_from_slice(&encoded, config::standard()) + .unwrap() + .0; + + // Verify that the deserialized instance matches the original instance + assert_eq!(validator_set, decoded); + } +} diff --git a/packages/rs-dpp/src/data_contract/document_type/methods/contested_vote_poll_for_document/v0/mod.rs b/packages/rs-dpp/src/data_contract/document_type/methods/contested_vote_poll_for_document/v0/mod.rs index d8f419a1a4..ac9911fe5b 100644 --- a/packages/rs-dpp/src/data_contract/document_type/methods/contested_vote_poll_for_document/v0/mod.rs +++ b/packages/rs-dpp/src/data_contract/document_type/methods/contested_vote_poll_for_document/v0/mod.rs @@ -3,12 +3,22 @@ use crate::data_contract::document_type::v0::DocumentTypeV0; use crate::document::{Document, DocumentV0Getters}; use crate::voting::vote_polls::contested_document_resource_vote_poll::ContestedDocumentResourceVotePoll; use crate::voting::vote_polls::VotePoll; +use platform_value::btreemap_extensions::BTreeValueMapPathHelper; +use platform_value::Value; +use std::collections::BTreeMap; impl DocumentTypeV0 { /// Figures out the prefunded voting balance (v0) for a document in a document type pub(in crate::data_contract::document_type) fn contested_vote_poll_for_document_v0( &self, document: &Document, + ) -> Option { + self.contested_vote_poll_for_document_properties_v0(document.properties()) + } + + pub(in crate::data_contract::document_type) fn contested_vote_poll_for_document_properties_v0( + &self, + document_properties: &BTreeMap, ) -> Option { self.indexes() .values() @@ -18,7 +28,11 @@ impl DocumentTypeV0 { .field_matches .iter() .all(|(field, field_match)| { - if let Some(value) = document.get(field) { + if let Some(value) = document_properties + .get_optional_at_path(field) + .ok() + .flatten() + { field_match.matches(value) } else { false @@ -29,7 +43,7 @@ impl DocumentTypeV0 { } }) .map(|index| { - let index_values = index.extract_values(document.properties()); + let index_values = index.extract_values(document_properties); VotePoll::ContestedDocumentResourceVotePoll(ContestedDocumentResourceVotePoll { contract_id: self.data_contract_id, document_type_name: self.name.clone(), diff --git a/packages/rs-dpp/src/data_contract/document_type/methods/mod.rs b/packages/rs-dpp/src/data_contract/document_type/methods/mod.rs index ca83589ccc..1c05a45304 100644 --- a/packages/rs-dpp/src/data_contract/document_type/methods/mod.rs +++ b/packages/rs-dpp/src/data_contract/document_type/methods/mod.rs @@ -138,6 +138,12 @@ pub trait DocumentTypeV0Methods { document: &Document, platform_version: &PlatformVersion, ) -> Result, ProtocolError>; + /// Gets the vote poll associated with a document + fn contested_vote_poll_for_document_properties( + &self, + document_properties: &BTreeMap, + platform_version: &PlatformVersion, + ) -> Result, ProtocolError>; } impl DocumentTypeV0Methods for DocumentTypeV0 { @@ -399,4 +405,26 @@ impl DocumentTypeV0Methods for DocumentTypeV0 { }), } } + + /// Gets the vote poll associated with a document + fn contested_vote_poll_for_document_properties( + &self, + document_properties: &BTreeMap, + platform_version: &PlatformVersion, + ) -> Result, ProtocolError> { + match platform_version + .dpp + .contract_versions + .document_type_versions + .methods + .contested_vote_poll_for_document + { + 0 => Ok(self.contested_vote_poll_for_document_properties_v0(document_properties)), + version => Err(ProtocolError::UnknownVersionMismatch { + method: "contested_vote_poll_for_document_properties".to_string(), + known_versions: vec![0], + received: version, + }), + } + } } diff --git a/packages/rs-dpp/src/data_contract/document_type/mod.rs b/packages/rs-dpp/src/data_contract/document_type/mod.rs index 89143a89a5..a87ceb3c9c 100644 --- a/packages/rs-dpp/src/data_contract/document_type/mod.rs +++ b/packages/rs-dpp/src/data_contract/document_type/mod.rs @@ -268,4 +268,14 @@ impl<'a> DocumentTypeV0Methods for DocumentTypeRef<'a> { } } } + fn contested_vote_poll_for_document_properties( + &self, + document_properties: &BTreeMap, + platform_version: &PlatformVersion, + ) -> Result, ProtocolError> { + match self { + DocumentTypeRef::V0(v0) => v0 + .contested_vote_poll_for_document_properties(document_properties, platform_version), + } + } } diff --git a/packages/rs-dpp/src/errors/consensus/basic/basic_error.rs b/packages/rs-dpp/src/errors/consensus/basic/basic_error.rs index ea33077b76..2b24a1e280 100644 --- a/packages/rs-dpp/src/errors/consensus/basic/basic_error.rs +++ b/packages/rs-dpp/src/errors/consensus/basic/basic_error.rs @@ -52,7 +52,7 @@ use crate::consensus::basic::identity::{ InvalidIdentityUpdateTransitionDisableKeysError, InvalidIdentityUpdateTransitionEmptyError, InvalidInstantAssetLockProofError, InvalidInstantAssetLockProofSignatureError, MissingMasterPublicKeyError, NotImplementedIdentityCreditWithdrawalTransitionPoolingError, - TooManyMasterPublicKeyError, + TooManyMasterPublicKeyError, WithdrawalOutputScriptNotAllowedWhenSigningWithOwnerKeyError, }; use crate::consensus::basic::invalid_identifier_error::InvalidIdentifierError; use crate::consensus::basic::state_transition::{ @@ -335,6 +335,11 @@ pub enum BasicError { InvalidIdentityCreditWithdrawalTransitionOutputScriptError, ), + #[error(transparent)] + WithdrawalOutputScriptNotAllowedWhenSigningWithOwnerKeyError( + WithdrawalOutputScriptNotAllowedWhenSigningWithOwnerKeyError, + ), + #[error(transparent)] InvalidIdentityCreditWithdrawalTransitionCoreFeeError( InvalidIdentityCreditWithdrawalTransitionCoreFeeError, diff --git a/packages/rs-dpp/src/errors/consensus/basic/identity/mod.rs b/packages/rs-dpp/src/errors/consensus/basic/identity/mod.rs index aafc111b85..3b411457fa 100644 --- a/packages/rs-dpp/src/errors/consensus/basic/identity/mod.rs +++ b/packages/rs-dpp/src/errors/consensus/basic/identity/mod.rs @@ -29,6 +29,7 @@ pub use invalid_instant_asset_lock_proof_signature_error::*; pub use missing_master_public_key_error::*; pub use not_implemented_identity_credit_withdrawal_transition_pooling_error::*; pub use too_many_master_public_key_error::*; +pub use withdrawal_output_script_not_allowed_when_signing_with_owner_key::*; mod data_contract_bounds_not_present_error; mod disabling_key_id_also_being_added_in_same_transition_error; @@ -62,3 +63,4 @@ mod invalid_instant_asset_lock_proof_signature_error; mod missing_master_public_key_error; mod not_implemented_identity_credit_withdrawal_transition_pooling_error; mod too_many_master_public_key_error; +mod withdrawal_output_script_not_allowed_when_signing_with_owner_key; diff --git a/packages/rs-dpp/src/errors/consensus/basic/identity/withdrawal_output_script_not_allowed_when_signing_with_owner_key.rs b/packages/rs-dpp/src/errors/consensus/basic/identity/withdrawal_output_script_not_allowed_when_signing_with_owner_key.rs new file mode 100644 index 0000000000..70f4c68b5d --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/basic/identity/withdrawal_output_script_not_allowed_when_signing_with_owner_key.rs @@ -0,0 +1,50 @@ +use crate::errors::ProtocolError; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; +use thiserror::Error; + +use crate::consensus::basic::BasicError; +use crate::consensus::ConsensusError; +use crate::identity::core_script::CoreScript; + +use crate::identity::KeyID; +use bincode::{Decode, Encode}; + +#[derive( + Error, Debug, Clone, PartialEq, Eq, Encode, Decode, PlatformSerialize, PlatformDeserialize, +)] +#[error("Withdrawal output script not allowed when signing with owner key {key_id}")] +#[platform_serialize(unversioned)] +pub struct WithdrawalOutputScriptNotAllowedWhenSigningWithOwnerKeyError { + output_script: CoreScript, + key_id: KeyID, +} + +/* + +DO NOT CHANGE ORDER OF FIELDS WITHOUT INTRODUCING OF NEW VERSION + +*/ + +impl WithdrawalOutputScriptNotAllowedWhenSigningWithOwnerKeyError { + pub fn new(output_script: CoreScript, key_id: KeyID) -> Self { + Self { + output_script, + key_id, + } + } + + pub fn output_script(&self) -> &CoreScript { + &self.output_script + } + + pub fn key_id(&self) -> KeyID { + self.key_id + } +} +impl From for ConsensusError { + fn from(err: WithdrawalOutputScriptNotAllowedWhenSigningWithOwnerKeyError) -> Self { + Self::BasicError( + BasicError::WithdrawalOutputScriptNotAllowedWhenSigningWithOwnerKeyError(err), + ) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/codes.rs b/packages/rs-dpp/src/errors/consensus/codes.rs index ca00dc1c2b..b238f55c02 100644 --- a/packages/rs-dpp/src/errors/consensus/codes.rs +++ b/packages/rs-dpp/src/errors/consensus/codes.rs @@ -153,6 +153,7 @@ impl ErrorWithCode for BasicError { Self::MasterPublicKeyUpdateError(_) => 10529, Self::IdentityAssetLockTransactionOutPointNotEnoughBalanceError(_) => 10530, Self::IdentityAssetLockStateTransitionReplayError(_) => 10531, + Self::WithdrawalOutputScriptNotAllowedWhenSigningWithOwnerKeyError(_) => 10532, // State Transition Errors: 10600-10699 Self::InvalidStateTransitionTypeError { .. } => 10600, @@ -215,6 +216,7 @@ impl ErrorWithCode for StateError { Self::DocumentContestNotJoinableError(_) => 40111, Self::DocumentContestIdentityAlreadyContestantError(_) => 40112, Self::DocumentContestDocumentWithSameIdAlreadyPresentError(_) => 40113, + Self::DocumentContestNotPaidForError(_) => 40114, // Identity Errors: 40200-40299 Self::IdentityAlreadyExistsError(_) => 40200, diff --git a/packages/rs-dpp/src/errors/consensus/state/document/document_contest_not_paid_for_error.rs b/packages/rs-dpp/src/errors/consensus/state/document/document_contest_not_paid_for_error.rs new file mode 100644 index 0000000000..9e6138c7a5 --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/state/document/document_contest_not_paid_for_error.rs @@ -0,0 +1,54 @@ +use crate::consensus::state::state_error::StateError; +use crate::consensus::ConsensusError; +use crate::errors::ProtocolError; +use crate::fee::Credits; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; +use platform_value::Identifier; +use thiserror::Error; + +#[derive( + Error, Debug, Clone, PartialEq, Eq, Encode, Decode, PlatformSerialize, PlatformDeserialize, +)] +#[error("Contest for document {document_id} was not paid for, needs payment of {expected_amount} Credits")] +#[platform_serialize(unversioned)] +pub struct DocumentContestNotPaidForError { + /* + + DO NOT CHANGE ORDER OF FIELDS WITHOUT INTRODUCING OF NEW VERSION + + */ + document_id: Identifier, + + expected_amount: Credits, + + paid_amount: Credits, +} + +impl DocumentContestNotPaidForError { + pub fn new(document_id: Identifier, expected_amount: Credits, paid_amount: Credits) -> Self { + Self { + document_id, + expected_amount, + paid_amount, + } + } + + pub fn document_id(&self) -> &Identifier { + &self.document_id + } + + pub fn expected_amount(&self) -> Credits { + self.expected_amount + } + + pub fn paid_amount(&self) -> Credits { + self.paid_amount + } +} + +impl From for ConsensusError { + fn from(err: DocumentContestNotPaidForError) -> Self { + Self::StateError(StateError::DocumentContestNotPaidForError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/state/document/mod.rs b/packages/rs-dpp/src/errors/consensus/state/document/mod.rs index 2a3441fe12..0c59e8741c 100644 --- a/packages/rs-dpp/src/errors/consensus/state/document/mod.rs +++ b/packages/rs-dpp/src/errors/consensus/state/document/mod.rs @@ -3,6 +3,7 @@ pub mod document_contest_currently_locked_error; pub mod document_contest_document_with_same_id_already_present_error; pub mod document_contest_identity_already_contestant; pub mod document_contest_not_joinable_error; +pub mod document_contest_not_paid_for_error; pub mod document_incorrect_purchase_price_error; pub mod document_not_for_sale_error; pub mod document_not_found_error; diff --git a/packages/rs-dpp/src/errors/consensus/state/state_error.rs b/packages/rs-dpp/src/errors/consensus/state/state_error.rs index ab98b5c6fe..8b0ac2b26b 100644 --- a/packages/rs-dpp/src/errors/consensus/state/state_error.rs +++ b/packages/rs-dpp/src/errors/consensus/state/state_error.rs @@ -33,6 +33,7 @@ use crate::consensus::state::document::document_contest_currently_locked_error:: use crate::consensus::state::document::document_contest_document_with_same_id_already_present_error::DocumentContestDocumentWithSameIdAlreadyPresentError; use crate::consensus::state::document::document_contest_identity_already_contestant::DocumentContestIdentityAlreadyContestantError; use crate::consensus::state::document::document_contest_not_joinable_error::DocumentContestNotJoinableError; +use crate::consensus::state::document::document_contest_not_paid_for_error::DocumentContestNotPaidForError; use crate::consensus::state::document::document_incorrect_purchase_price_error::DocumentIncorrectPurchasePriceError; use crate::consensus::state::document::document_not_for_sale_error::DocumentNotForSaleError; use crate::consensus::state::identity::identity_public_key_already_exists_for_unique_contract_bounds_error::IdentityPublicKeyAlreadyExistsForUniqueContractBoundsError; @@ -81,6 +82,9 @@ pub enum StateError { #[error(transparent)] DocumentContestIdentityAlreadyContestantError(DocumentContestIdentityAlreadyContestantError), + #[error(transparent)] + DocumentContestNotPaidForError(DocumentContestNotPaidForError), + #[error(transparent)] DocumentContestDocumentWithSameIdAlreadyPresentError( DocumentContestDocumentWithSameIdAlreadyPresentError, diff --git a/packages/rs-dpp/src/fee/default_costs/mod.rs b/packages/rs-dpp/src/fee/default_costs/mod.rs index 9af68bb143..b1ad372c07 100644 --- a/packages/rs-dpp/src/fee/default_costs/mod.rs +++ b/packages/rs-dpp/src/fee/default_costs/mod.rs @@ -1,32 +1,3 @@ -// MIT LICENSE -// -// Copyright (c) 2021 Dash Core Group -// -// Permission is hereby granted, free of charge, to any -// person obtaining a copy of this software and associated -// documentation files (the "Software"), to deal in the -// Software without restriction, including without -// limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice -// shall be included in all copies or substantial portions -// of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. -// - //! Fee costs //! //! Fee costs for Known Platform operations @@ -34,13 +5,22 @@ use crate::block::epoch::{Epoch, EpochIndex}; use crate::fee::Credits; -use platform_version::version::fee::FeeVersion; -use platform_version::version::PlatformVersion; +use platform_version::version::fee::{ + FeeVersion, FeeVersionFieldsBeforeVersion4, FeeVersionNumber, +}; use std::collections::BTreeMap; pub mod constants; -pub type CachedEpochIndexFeeVersions = BTreeMap; +pub type CachedEpochIndexFeeVersions = BTreeMap; +pub type EpochIndexFeeVersionsForStorage = BTreeMap; + +// This is type only meant for deserialization because of an issue +// The issue was that the platform state was stored with FeeVersions in it before version 1.4 +// When we would add new fields we would be unable to deserialize +// This FeeProcessingVersionFieldsBeforeVersion4 is how things were before version 1.4 was released +pub type CachedEpochIndexFeeVersionsFieldsBeforeVersion4 = + BTreeMap; /// A Known Cost Item is an item that changes costs depending on the Epoch #[derive(Eq, PartialEq, Copy, Clone, Hash)] @@ -143,7 +123,10 @@ impl KnownCostItem { pub trait EpochCosts { /// Get the closest epoch in the past that has a cost table /// This is where the base costs last changed - fn active_fee_version(&self, cached_fee_version: &CachedEpochIndexFeeVersions) -> FeeVersion; + fn active_fee_version( + &self, + cached_fee_version: &CachedEpochIndexFeeVersions, + ) -> &'static FeeVersion; /// Get the cost for the known cost item fn cost_for_known_cost_item( &self, @@ -154,18 +137,20 @@ pub trait EpochCosts { impl EpochCosts for Epoch { /// Get the active fee version for an epoch - fn active_fee_version(&self, cached_fee_version: &CachedEpochIndexFeeVersions) -> FeeVersion { + fn active_fee_version( + &self, + cached_fee_version: &CachedEpochIndexFeeVersions, + ) -> &'static FeeVersion { // If the exact EpochIndex is matching to a FeeVersion update if let Some(fee_version) = cached_fee_version.get(&self.index) { - return fee_version.clone(); + return fee_version; } // else return the FeeVersion at lower adjacent EpochIndex (if available, else the FeeVersion of first PlatformVersion) cached_fee_version .range(..=self.index) .next_back() - .map(|(_, fee_version)| fee_version) - .unwrap_or_else(|| &PlatformVersion::first().fee_version) - .clone() + .map(|(_, fee_version)| *fee_version) + .unwrap_or_else(|| FeeVersion::first()) } /// Get the cost for the known cost item diff --git a/packages/rs-dpp/src/fee/fee_result/refunds.rs b/packages/rs-dpp/src/fee/fee_result/refunds.rs index f95fd379d2..90b93159a4 100644 --- a/packages/rs-dpp/src/fee/fee_result/refunds.rs +++ b/packages/rs-dpp/src/fee/fee_result/refunds.rs @@ -182,10 +182,10 @@ impl IntoIterator for FeeRefunds { mod tests { use super::*; use once_cell::sync::Lazy; - use platform_version::version::PlatformVersion; + use platform_version::version::fee::FeeVersion; static EPOCH_CHANGE_FEE_VERSION_TEST: Lazy = - Lazy::new(|| BTreeMap::from([(0, PlatformVersion::first().fee_version.clone())])); + Lazy::new(|| BTreeMap::from([(0, FeeVersion::first())])); mod from_storage_removal { use super::*; diff --git a/packages/rs-dpp/src/identity/identity_public_key/key_type.rs b/packages/rs-dpp/src/identity/identity_public_key/key_type.rs index d91bec6626..2d64045452 100644 --- a/packages/rs-dpp/src/identity/identity_public_key/key_type.rs +++ b/packages/rs-dpp/src/identity/identity_public_key/key_type.rs @@ -1,4 +1,3 @@ -#[cfg(feature = "random-public-keys")] use crate::util::hash::ripemd160_sha256; use anyhow::bail; use bincode::{Decode, Encode}; @@ -8,16 +7,14 @@ use ciborium::value::Value as CborValue; use dashcore::secp256k1::rand::rngs::StdRng as EcdsaRng; #[cfg(feature = "random-public-keys")] use dashcore::secp256k1::rand::SeedableRng; -#[cfg(feature = "random-public-keys")] use dashcore::secp256k1::Secp256k1; -#[cfg(feature = "random-public-keys")] use dashcore::Network; use itertools::Itertools; use lazy_static::lazy_static; use crate::fee::Credits; use crate::version::PlatformVersion; -use crate::ProtocolError; +use crate::{InvalidVectorSizeError, ProtocolError}; #[cfg(feature = "random-public-keys")] use rand::rngs::StdRng; #[cfg(feature = "random-public-keys")] @@ -204,6 +201,73 @@ impl KeyType { } } + /// Gets the public key data for a private key depending on the key type + pub fn public_key_data_from_private_key_data( + &self, + private_key_bytes: &[u8], + network: Network, + ) -> Result, ProtocolError> { + match self { + KeyType::ECDSA_SECP256K1 => { + let secp = Secp256k1::new(); + let secret_key = dashcore::secp256k1::SecretKey::from_slice(private_key_bytes) + .map_err(|e| ProtocolError::Generic(e.to_string()))?; + let private_key = dashcore::PrivateKey::new(secret_key, network); + + Ok(private_key.public_key(&secp).to_bytes()) + } + KeyType::BLS12_381 => { + #[cfg(feature = "bls-signatures")] + { + let private_key = + bls_signatures::PrivateKey::from_bytes(private_key_bytes, false) + .map_err(|e| ProtocolError::Generic(e.to_string()))?; + let public_key_bytes = private_key + .g1_element() + .expect("expected to get a public key from a bls private key") + .to_bytes() + .to_vec(); + Ok(public_key_bytes) + } + #[cfg(not(feature = "bls-signatures"))] + return Err(ProtocolError::NotSupported( + "Converting a private key to a bls public key is not supported without the bls-signatures feature".to_string(), + )); + } + KeyType::ECDSA_HASH160 => { + let secp = Secp256k1::new(); + let secret_key = dashcore::secp256k1::SecretKey::from_slice(private_key_bytes) + .map_err(|e| ProtocolError::Generic(e.to_string()))?; + let private_key = dashcore::PrivateKey::new(secret_key, network); + + Ok(ripemd160_sha256(private_key.public_key(&secp).to_bytes().as_slice()).to_vec()) + } + KeyType::EDDSA_25519_HASH160 => { + #[cfg(feature = "ed25519-dalek")] + { + let key_pair = ed25519_dalek::SigningKey::from_bytes( + &private_key_bytes.try_into().map_err(|_| { + ProtocolError::InvalidVectorSizeError(InvalidVectorSizeError::new( + 32, + private_key_bytes.len(), + )) + })?, + ); + Ok(ripemd160_sha256(key_pair.verifying_key().to_bytes().as_slice()).to_vec()) + } + #[cfg(not(feature = "ed25519-dalek"))] + return Err(ProtocolError::NotSupported( + "Converting a private key to a eddsa hash 160 is not supported without the ed25519-dalek feature".to_string(), + )); + } + KeyType::BIP13_SCRIPT_HASH => { + return Err(ProtocolError::NotSupported( + "Converting a private key to a script hash is not supported".to_string(), + )); + } + } + } + #[cfg(feature = "random-public-keys")] /// Gets the default size of the public key pub fn random_public_and_private_key_data_v0(&self, rng: &mut StdRng) -> (Vec, Vec) { @@ -241,7 +305,7 @@ impl KeyType { KeyType::EDDSA_25519_HASH160 => { let key_pair = ed25519_dalek::SigningKey::generate(rng); ( - key_pair.verifying_key().to_bytes().to_vec(), + ripemd160_sha256(key_pair.verifying_key().to_bytes().as_slice()).to_vec(), key_pair.to_bytes().to_vec(), ) } diff --git a/packages/rs-dpp/src/identity/identity_public_key/methods/hash/mod.rs b/packages/rs-dpp/src/identity/identity_public_key/methods/hash/mod.rs index 6978a3035d..b22a3f0c26 100644 --- a/packages/rs-dpp/src/identity/identity_public_key/methods/hash/mod.rs +++ b/packages/rs-dpp/src/identity/identity_public_key/methods/hash/mod.rs @@ -2,6 +2,7 @@ mod v0; use crate::identity::IdentityPublicKey; use crate::ProtocolError; +use dashcore::Network; pub use v0::*; impl IdentityPublicKeyHashMethodsV0 for IdentityPublicKey { @@ -10,4 +11,14 @@ impl IdentityPublicKeyHashMethodsV0 for IdentityPublicKey { IdentityPublicKey::V0(v0) => v0.public_key_hash(), } } + + fn validate_private_key_bytes( + &self, + private_key_bytes: &[u8], + network: Network, + ) -> Result { + match self { + IdentityPublicKey::V0(v0) => v0.validate_private_key_bytes(private_key_bytes, network), + } + } } diff --git a/packages/rs-dpp/src/identity/identity_public_key/methods/hash/v0/mod.rs b/packages/rs-dpp/src/identity/identity_public_key/methods/hash/v0/mod.rs index 7b656292e3..b11c79c31f 100644 --- a/packages/rs-dpp/src/identity/identity_public_key/methods/hash/v0/mod.rs +++ b/packages/rs-dpp/src/identity/identity_public_key/methods/hash/v0/mod.rs @@ -1,6 +1,14 @@ use crate::ProtocolError; +use dashcore::Network; pub trait IdentityPublicKeyHashMethodsV0 { /// Get the original public key hash fn public_key_hash(&self) -> Result<[u8; 20], ProtocolError>; + + /// Verifies that the private key bytes match this identity public key + fn validate_private_key_bytes( + &self, + private_key_bytes: &[u8], + network: Network, + ) -> Result; } diff --git a/packages/rs-dpp/src/identity/identity_public_key/purpose.rs b/packages/rs-dpp/src/identity/identity_public_key/purpose.rs index dbadfa5748..36255fdc45 100644 --- a/packages/rs-dpp/src/identity/identity_public_key/purpose.rs +++ b/packages/rs-dpp/src/identity/identity_public_key/purpose.rs @@ -1,4 +1,6 @@ -use crate::identity::Purpose::{AUTHENTICATION, DECRYPTION, ENCRYPTION, SYSTEM, TRANSFER, VOTING}; +use crate::identity::Purpose::{ + AUTHENTICATION, DECRYPTION, ENCRYPTION, OWNER, SYSTEM, TRANSFER, VOTING, +}; use anyhow::bail; use bincode::{Decode, Encode}; #[cfg(feature = "cbor")] @@ -37,6 +39,8 @@ pub enum Purpose { SYSTEM = 4, /// this key cannot be used for signing documents VOTING = 5, + /// this key is used to prove ownership of a masternode or evonode + OWNER = 6, } impl From for [u8; 1] { @@ -54,6 +58,7 @@ impl From for &'static [u8; 1] { TRANSFER => &[3], SYSTEM => &[4], VOTING => &[5], + OWNER => &[6], } } } @@ -68,6 +73,7 @@ impl TryFrom for Purpose { 3 => Ok(TRANSFER), 4 => Ok(SYSTEM), 5 => Ok(VOTING), + 6 => Ok(OWNER), value => bail!("unrecognized purpose: {}", value), } } @@ -83,6 +89,7 @@ impl TryFrom for Purpose { 3 => Ok(TRANSFER), 4 => Ok(SYSTEM), 5 => Ok(VOTING), + 6 => Ok(OWNER), value => bail!("unrecognized purpose: {}", value), } } @@ -102,8 +109,15 @@ impl std::fmt::Display for Purpose { impl Purpose { /// The full range of purposes - pub fn full_range() -> [Purpose; 5] { - [AUTHENTICATION, ENCRYPTION, DECRYPTION, TRANSFER, VOTING] + pub fn full_range() -> [Purpose; 6] { + [ + AUTHENTICATION, + ENCRYPTION, + DECRYPTION, + TRANSFER, + VOTING, + OWNER, + ] } /// Just the authentication and withdraw purposes pub fn searchable_purposes() -> [Purpose; 3] { @@ -113,8 +127,4 @@ impl Purpose { pub fn encryption_decryption() -> [Purpose; 2] { [ENCRYPTION, DECRYPTION] } - /// The last purpose - pub fn last() -> Purpose { - Self::TRANSFER - } } diff --git a/packages/rs-dpp/src/identity/identity_public_key/random.rs b/packages/rs-dpp/src/identity/identity_public_key/random.rs index 0dea7a5dee..dec286b927 100644 --- a/packages/rs-dpp/src/identity/identity_public_key/random.rs +++ b/packages/rs-dpp/src/identity/identity_public_key/random.rs @@ -467,6 +467,149 @@ impl IdentityPublicKey { } } + /// Generates a random ECDSA critical-level authentication key for a masternode owner. + /// + /// This function generates a random key that can be used for owner authentication in a masternode context. + /// The function accepts an optional seed for deterministic key generation, or uses entropy-based randomness if no seed is provided. + /// + /// # Parameters + /// + /// * `id`: The identifier (`KeyID`) for the masternode owner key. + /// * `seed`: An optional `u64` value used to seed the random number generator. If `None`, the RNG will be seeded from entropy. + /// * `platform_version`: A reference to the `PlatformVersion` struct, which is used to determine the correct key structure version. + /// + /// # Returns + /// + /// Returns a tuple containing the generated `IdentityPublicKey` for the masternode owner and the corresponding private key as a byte vector. + /// + /// # Errors + /// + /// Returns a `ProtocolError` if the platform version is not supported. + pub fn random_masternode_owner_key( + id: KeyID, + seed: Option, + platform_version: &PlatformVersion, + ) -> Result<(Self, Vec), ProtocolError> { + let mut rng = match seed { + None => StdRng::from_entropy(), + Some(seed_value) => StdRng::seed_from_u64(seed_value), + }; + Self::random_masternode_owner_key_with_rng(id, &mut rng, platform_version) + } + + /// Generates a random ECDSA critical-level authentication key for a masternode owner using a custom RNG. + /// + /// This function generates a random key using a given random number generator (RNG). This is useful when specific control over the randomness is needed. + /// + /// # Parameters + /// + /// * `id`: The identifier (`KeyID`) for the masternode owner key. + /// * `rng`: A mutable reference to a `StdRng` instance used to generate randomness. + /// * `platform_version`: A reference to the `PlatformVersion` struct, which is used to determine the correct key structure version. + /// + /// # Returns + /// + /// Returns a tuple containing the generated `IdentityPublicKey` for the masternode owner and the corresponding private key as a byte vector. + /// + /// # Errors + /// + /// Returns a `ProtocolError` if the platform version is not supported. + pub fn random_masternode_owner_key_with_rng( + id: KeyID, + rng: &mut StdRng, + platform_version: &PlatformVersion, + ) -> Result<(Self, Vec), ProtocolError> { + match platform_version + .dpp + .identity_versions + .identity_key_structure_version + { + 0 => { + let (key, private_key) = + IdentityPublicKeyV0::random_owner_key_with_rng(id, rng, platform_version)?; + Ok((key.into(), private_key)) + } + version => Err(ProtocolError::UnknownVersionMismatch { + method: "IdentityPublicKey::random_masternode_owner_key_with_rng".to_string(), + known_versions: vec![0], + received: version, + }), + } + } + + /// Generates a random ECDSA critical-level transfer key for a masternode. + /// + /// This function generates a random key for use in transferring ownership of a masternode. An optional seed can be provided for deterministic key generation, or entropy-based randomness is used if no seed is given. + /// + /// # Parameters + /// + /// * `id`: The identifier (`KeyID`) for the masternode transfer key. + /// * `seed`: An optional `u64` value used to seed the random number generator. If `None`, the RNG will be seeded from entropy. + /// * `platform_version`: A reference to the `PlatformVersion` struct, which is used to determine the correct key structure version. + /// + /// # Returns + /// + /// Returns a tuple containing the generated `IdentityPublicKey` for the masternode transfer key and the corresponding private key as a byte vector. + /// + /// # Errors + /// + /// Returns a `ProtocolError` if the platform version is not supported. + pub fn random_masternode_transfer_key( + id: KeyID, + seed: Option, + platform_version: &PlatformVersion, + ) -> Result<(Self, Vec), ProtocolError> { + let mut rng = match seed { + None => StdRng::from_entropy(), + Some(seed_value) => StdRng::seed_from_u64(seed_value), + }; + Self::random_masternode_transfer_key_with_rng(id, &mut rng, platform_version) + } + + /// Generates a random ECDSA critical-level transfer key for a masternode using a custom RNG. + /// + /// This function generates a random key for masternode transfers using a given random number generator (RNG). + /// + /// # Parameters + /// + /// * `id`: The identifier (`KeyID`) for the masternode transfer key. + /// * `rng`: A mutable reference to a `StdRng` instance used to generate randomness. + /// * `platform_version`: A reference to the `PlatformVersion` struct, which is used to determine the correct key structure version. + /// + /// # Returns + /// + /// Returns a tuple containing the generated `IdentityPublicKey` for the masternode transfer key and the corresponding private key as a byte vector. + /// + /// # Errors + /// + /// Returns a `ProtocolError` if the platform version is not supported. + pub fn random_masternode_transfer_key_with_rng( + id: KeyID, + rng: &mut StdRng, + platform_version: &PlatformVersion, + ) -> Result<(Self, Vec), ProtocolError> { + match platform_version + .dpp + .identity_versions + .identity_key_structure_version + { + 0 => { + let (key, private_key) = + IdentityPublicKeyV0::random_masternode_transfer_key_with_rng( + id, + rng, + platform_version, + )?; + Ok((key.into(), private_key)) + } + version => Err(ProtocolError::UnknownVersionMismatch { + method: "IdentityPublicKey::random_masternode_transfer_key_with_rng".to_string(), + known_versions: vec![0], + received: version, + }), + } + } + /// Generates a random ECDSA high-level authentication public key along with its corresponding private key. /// /// This method constructs a random ECDSA (using the secp256k1 curve) high-level authentication public key diff --git a/packages/rs-dpp/src/identity/identity_public_key/v0/methods/mod.rs b/packages/rs-dpp/src/identity/identity_public_key/v0/methods/mod.rs index 05232ed22a..891bd5ed82 100644 --- a/packages/rs-dpp/src/identity/identity_public_key/v0/methods/mod.rs +++ b/packages/rs-dpp/src/identity/identity_public_key/v0/methods/mod.rs @@ -5,7 +5,9 @@ use crate::util::hash::ripemd160_sha256; use crate::ProtocolError; use anyhow::anyhow; use dashcore::hashes::Hash; -use dashcore::PublicKey as ECDSAPublicKey; +use dashcore::key::Secp256k1; +use dashcore::secp256k1::SecretKey; +use dashcore::{Network, PublicKey as ECDSAPublicKey}; use platform_value::Bytes20; impl IdentityPublicKeyHashMethodsV0 for IdentityPublicKeyV0 { @@ -45,4 +47,213 @@ impl IdentityPublicKeyHashMethodsV0 for IdentityPublicKeyV0 { } } } + + fn validate_private_key_bytes( + &self, + private_key_bytes: &[u8], + network: Network, + ) -> Result { + match self.key_type { + KeyType::ECDSA_SECP256K1 => { + let secp = Secp256k1::new(); + let secret_key = match SecretKey::from_slice(private_key_bytes) { + Ok(secret_key) => secret_key, + Err(_) => return Ok(false), + }; + let private_key = dashcore::PrivateKey::new(secret_key, network); + + Ok(private_key.public_key(&secp).to_bytes() == self.data.as_slice()) + } + KeyType::BLS12_381 => { + #[cfg(feature = "bls-signatures")] + { + let private_key = + match bls_signatures::PrivateKey::from_bytes(private_key_bytes, false) { + Ok(secret_key) => secret_key, + Err(_) => return Ok(false), + }; + let g1_element = match private_key.g1_element() { + Ok(g1_element) => g1_element, + Err(_) => return Ok(false), + }; + + Ok(g1_element.to_bytes().as_slice() == self.data.as_slice()) + } + #[cfg(not(feature = "bls-signatures"))] + return Err(ProtocolError::NotSupported( + "Converting a private key to a bls public key is not supported without the bls-signatures feature".to_string(), + )); + } + KeyType::ECDSA_HASH160 => { + let secp = Secp256k1::new(); + let secret_key = match SecretKey::from_slice(private_key_bytes) { + Ok(secret_key) => secret_key, + Err(_) => return Ok(false), + }; + let private_key = dashcore::PrivateKey::new(secret_key, network); + + Ok( + ripemd160_sha256(private_key.public_key(&secp).to_bytes().as_slice()) + .as_slice() + == self.data.as_slice(), + ) + } + KeyType::EDDSA_25519_HASH160 => { + #[cfg(feature = "ed25519-dalek")] + { + let secret_key = match private_key_bytes.try_into() { + Ok(secret_key) => secret_key, + Err(_) => return Ok(false), + }; + let key_pair = ed25519_dalek::SigningKey::from_bytes(&secret_key); + Ok( + ripemd160_sha256(key_pair.verifying_key().to_bytes().as_slice()).as_slice() + == self.data.as_slice(), + ) + } + #[cfg(not(feature = "ed25519-dalek"))] + return Err(ProtocolError::NotSupported( + "Converting a private key to a eddsa hash 160 is not supported without the ed25519-dalek feature".to_string(), + )); + } + KeyType::BIP13_SCRIPT_HASH => { + return Err(ProtocolError::NotSupported( + "Converting a private key to a script hash is not supported".to_string(), + )); + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::identity::{Purpose, SecurityLevel}; + use dashcore::Network; + use dpp::version::PlatformVersion; + use rand::rngs::StdRng; + use rand::SeedableRng; + + #[cfg(feature = "random-public-keys")] + #[test] + fn test_validate_private_key_bytes_with_random_keys() { + let platform_version = PlatformVersion::latest(); + let mut rng = StdRng::from_entropy(); + + // Test for ECDSA_SECP256K1 + let key_type = KeyType::ECDSA_SECP256K1; + let (public_key_data, private_key_data) = key_type + .random_public_and_private_key_data(&mut rng, &platform_version) + .expect("expected to generate random keys"); + + let identity_public_key = IdentityPublicKeyV0 { + id: 1, + purpose: Purpose::AUTHENTICATION, + security_level: SecurityLevel::HIGH, + contract_bounds: None, + key_type, + data: public_key_data.into(), + read_only: false, + disabled_at: None, + }; + + // Validate that the private key matches the public key + assert_eq!( + identity_public_key + .validate_private_key_bytes(&private_key_data, Network::Testnet) + .unwrap(), + true + ); + + // Test with an invalid private key + let invalid_private_key_bytes = vec![0u8; private_key_data.len()]; + assert_eq!( + identity_public_key + .validate_private_key_bytes(&invalid_private_key_bytes, Network::Testnet) + .unwrap(), + false + ); + } + + #[cfg(all(feature = "random-public-keys", feature = "bls-signatures"))] + #[test] + fn test_validate_private_key_bytes_with_random_keys_bls12_381() { + let platform_version = PlatformVersion::latest(); + let mut rng = StdRng::from_entropy(); + + // Test for BLS12_381 + let key_type = KeyType::BLS12_381; + let (public_key_data, private_key_data) = key_type + .random_public_and_private_key_data(&mut rng, &platform_version) + .expect("expected to generate random keys"); + + let identity_public_key = IdentityPublicKeyV0 { + id: 2, + purpose: Purpose::AUTHENTICATION, + security_level: SecurityLevel::HIGH, + contract_bounds: None, + key_type, + data: public_key_data.into(), + read_only: false, + disabled_at: None, + }; + + // Validate that the private key matches the public key + assert_eq!( + identity_public_key + .validate_private_key_bytes(&private_key_data, Network::Testnet) + .unwrap(), + true + ); + + // Test with an invalid private key + let invalid_private_key_bytes = vec![0u8; private_key_data.len()]; + assert_eq!( + identity_public_key + .validate_private_key_bytes(&invalid_private_key_bytes, Network::Testnet) + .unwrap(), + false + ); + } + + #[cfg(all(feature = "random-public-keys", feature = "ed25519-dalek"))] + #[test] + fn test_validate_private_key_bytes_with_random_keys_eddsa_25519_hash160() { + let platform_version = PlatformVersion::latest(); + let mut rng = StdRng::from_entropy(); + + // Test for EDDSA_25519_HASH160 + let key_type = KeyType::EDDSA_25519_HASH160; + let (public_key_data, private_key_data) = key_type + .random_public_and_private_key_data(&mut rng, &platform_version) + .expect("expected to generate random keys"); + + let identity_public_key = IdentityPublicKeyV0 { + id: 3, + purpose: Purpose::AUTHENTICATION, + security_level: SecurityLevel::HIGH, + contract_bounds: None, + key_type, + data: public_key_data.into(), + read_only: false, + disabled_at: None, + }; + + // Validate that the private key matches the public key + assert_eq!( + identity_public_key + .validate_private_key_bytes(&private_key_data, Network::Testnet) + .unwrap(), + true + ); + + // Test with an invalid private key + let invalid_private_key_bytes = vec![0u8; private_key_data.len()]; + assert_eq!( + identity_public_key + .validate_private_key_bytes(&invalid_private_key_bytes, Network::Testnet) + .unwrap(), + false + ); + } } diff --git a/packages/rs-dpp/src/identity/identity_public_key/v0/random.rs b/packages/rs-dpp/src/identity/identity_public_key/v0/random.rs index 13afdd673f..162e836e1b 100644 --- a/packages/rs-dpp/src/identity/identity_public_key/v0/random.rs +++ b/packages/rs-dpp/src/identity/identity_public_key/v0/random.rs @@ -1,7 +1,7 @@ use crate::identity::contract_bounds::ContractBounds; use crate::identity::identity_public_key::v0::IdentityPublicKeyV0; use crate::identity::KeyType::{ECDSA_HASH160, ECDSA_SECP256K1}; -use crate::identity::Purpose::{AUTHENTICATION, VOTING}; +use crate::identity::Purpose::{AUTHENTICATION, OWNER, TRANSFER, VOTING}; use crate::identity::SecurityLevel::{CRITICAL, HIGH, MASTER, MEDIUM}; use crate::identity::{KeyCount, KeyID, KeyType, Purpose, SecurityLevel}; use crate::version::PlatformVersion; @@ -245,6 +245,58 @@ impl IdentityPublicKeyV0 { )) } + pub fn random_owner_key_with_rng( + id: KeyID, + rng: &mut StdRng, + platform_version: &PlatformVersion, + ) -> Result<(Self, Vec), ProtocolError> { + let key_type = ECDSA_HASH160; + let purpose = OWNER; + let security_level = CRITICAL; + let read_only = true; + let (data, private_data) = + key_type.random_public_and_private_key_data(rng, platform_version)?; + Ok(( + IdentityPublicKeyV0 { + id, + key_type, + purpose, + security_level, + read_only, + disabled_at: None, + data: data.into(), + contract_bounds: None, + }, + private_data, + )) + } + + pub fn random_masternode_transfer_key_with_rng( + id: KeyID, + rng: &mut StdRng, + platform_version: &PlatformVersion, + ) -> Result<(Self, Vec), ProtocolError> { + let key_type = ECDSA_HASH160; + let purpose = TRANSFER; + let security_level = CRITICAL; + let read_only = true; + let (data, private_data) = + key_type.random_public_and_private_key_data(rng, platform_version)?; + Ok(( + IdentityPublicKeyV0 { + id, + key_type, + purpose, + security_level, + read_only, + disabled_at: None, + data: data.into(), + contract_bounds: None, + }, + private_data, + )) + } + pub fn random_ecdsa_critical_level_authentication_key_with_rng( id: KeyID, rng: &mut StdRng, diff --git a/packages/rs-dpp/src/state_transition/mod.rs b/packages/rs-dpp/src/state_transition/mod.rs index bc20c6ab0a..cd97cae4ae 100644 --- a/packages/rs-dpp/src/state_transition/mod.rs +++ b/packages/rs-dpp/src/state_transition/mod.rs @@ -152,8 +152,8 @@ macro_rules! call_getter_method_identity_signed { StateTransition::DataContractCreate(st) => Some(st.$method($args)), StateTransition::DataContractUpdate(st) => Some(st.$method($args)), StateTransition::DocumentsBatch(st) => Some(st.$method($args)), - StateTransition::IdentityCreate(st) => None, - StateTransition::IdentityTopUp(st) => None, + StateTransition::IdentityCreate(_) => None, + StateTransition::IdentityTopUp(_) => None, StateTransition::IdentityCreditWithdrawal(st) => Some(st.$method($args)), StateTransition::IdentityUpdate(st) => Some(st.$method($args)), StateTransition::IdentityCreditTransfer(st) => Some(st.$method($args)), @@ -165,8 +165,8 @@ macro_rules! call_getter_method_identity_signed { StateTransition::DataContractCreate(st) => Some(st.$method()), StateTransition::DataContractUpdate(st) => Some(st.$method()), StateTransition::DocumentsBatch(st) => Some(st.$method()), - StateTransition::IdentityCreate(_st) => None, - StateTransition::IdentityTopUp(_st) => None, + StateTransition::IdentityCreate(_) => None, + StateTransition::IdentityTopUp(_) => None, StateTransition::IdentityCreditWithdrawal(st) => Some(st.$method()), StateTransition::IdentityUpdate(st) => Some(st.$method()), StateTransition::IdentityCreditTransfer(st) => Some(st.$method()), diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_base_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_base_transition/mod.rs index 25dd569fb3..6d80cc2d87 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_base_transition/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_base_transition/mod.rs @@ -37,7 +37,7 @@ use std::collections::BTreeMap; derive(Serialize, Deserialize) )] pub enum DocumentBaseTransition { - #[display(fmt = "V0({})", "_0")] + #[display("V0({})", "_0")] V0(DocumentBaseTransitionV0), } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_base_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_base_transition/v0/mod.rs index 8392b81223..f5b245bece 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_base_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_base_transition/v0/mod.rs @@ -35,7 +35,7 @@ use crate::{data_contract::DataContract, errors::ProtocolError}; serde(rename_all = "camelCase") )] #[display( - fmt = "ID: {}, Type: {}, Contract ID: {}", + "ID: {}, Type: {}, Contract ID: {}", "id", "document_type_name", "data_contract_id" diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_create_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_create_transition/mod.rs index 2af4a2174f..cde6d5ae29 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_create_transition/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_create_transition/mod.rs @@ -22,7 +22,7 @@ pub use v0::DocumentCreateTransitionV0; derive(Serialize, Deserialize) )] pub enum DocumentCreateTransition { - #[display(fmt = "V0({})", "_0")] + #[display("V0({})", "_0")] V0(DocumentCreateTransitionV0), } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_create_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_create_transition/v0/mod.rs index b15cdf0e59..27c968b20b 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_create_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_create_transition/v0/mod.rs @@ -52,7 +52,7 @@ pub use super::super::document_base_transition::IDENTIFIER_FIELDS; derive(Serialize, Deserialize), serde(rename_all = "camelCase") )] -#[display(fmt = "Base: {}, Entropy: {:?}, Data: {:?}", "base", "entropy", "data")] +#[display("Base: {}, Entropy: {:?}, Data: {:?}", "base", "entropy", "data")] pub struct DocumentCreateTransitionV0 { /// Document Base Transition #[cfg_attr(feature = "state-transition-serde-conversion", serde(flatten))] diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_delete_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_delete_transition/mod.rs index 7a0f8fb2a6..0ca94ce886 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_delete_transition/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_delete_transition/mod.rs @@ -14,6 +14,6 @@ pub use v0::*; derive(Serialize, Deserialize) )] pub enum DocumentDeleteTransition { - #[display(fmt = "V0({})", "_0")] + #[display("V0({})", "_0")] V0(DocumentDeleteTransitionV0), } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_delete_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_delete_transition/v0/mod.rs index 813ea0b2dd..34d4ac9855 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_delete_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_delete_transition/v0/mod.rs @@ -17,7 +17,7 @@ pub use super::super::document_base_transition::IDENTIFIER_FIELDS; derive(Serialize, Deserialize), serde(rename_all = "camelCase") )] -#[display(fmt = "Base: {}", "base")] +#[display("Base: {}", "base")] pub struct DocumentDeleteTransitionV0 { #[cfg_attr(feature = "state-transition-serde-conversion", serde(flatten))] pub base: DocumentBaseTransition, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_purchase_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_purchase_transition/mod.rs index 9a5664cfaa..97ee83ec73 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_purchase_transition/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_purchase_transition/mod.rs @@ -14,6 +14,6 @@ pub use v0::*; derive(Serialize, Deserialize) )] pub enum DocumentPurchaseTransition { - #[display(fmt = "V0({})", "_0")] + #[display("V0({})", "_0")] V0(DocumentPurchaseTransitionV0), } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_purchase_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_purchase_transition/v0/mod.rs index 255310c394..5a4ca1e8ba 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_purchase_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_purchase_transition/v0/mod.rs @@ -19,7 +19,7 @@ pub use super::super::document_base_transition::IDENTIFIER_FIELDS; derive(Serialize, Deserialize), serde(rename_all = "camelCase") )] -#[display(fmt = "Base: {}", "base")] +#[display("Base: {}", "base")] pub struct DocumentPurchaseTransitionV0 { #[cfg_attr(feature = "state-transition-serde-conversion", serde(flatten))] pub base: DocumentBaseTransition, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_replace_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_replace_transition/mod.rs index 8e805318b5..e5dd1e7715 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_replace_transition/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_replace_transition/mod.rs @@ -21,7 +21,7 @@ pub use v0::*; derive(Serialize, Deserialize) )] pub enum DocumentReplaceTransition { - #[display(fmt = "V0({})", "_0")] + #[display("V0({})", "_0")] V0(DocumentReplaceTransitionV0), } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_replace_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_replace_transition/v0/mod.rs index 2c7f96e8e4..13833cabaf 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_replace_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_replace_transition/v0/mod.rs @@ -31,7 +31,7 @@ mod property_names { derive(Serialize, Deserialize), serde(rename_all = "camelCase") )] -#[display(fmt = "Base: {}, Revision: {}, Data: {:?}", "base", "revision", "data")] +#[display("Base: {}, Revision: {}, Data: {:?}", "base", "revision", "data")] pub struct DocumentReplaceTransitionV0 { #[cfg_attr(feature = "state-transition-serde-conversion", serde(flatten))] pub base: DocumentBaseTransition, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_transfer_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_transfer_transition/mod.rs index e2185f76b0..d784dca011 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_transfer_transition/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_transfer_transition/mod.rs @@ -14,6 +14,6 @@ pub use v0::*; derive(Serialize, Deserialize) )] pub enum DocumentTransferTransition { - #[display(fmt = "V0({})", "_0")] + #[display("V0({})", "_0")] V0(DocumentTransferTransitionV0), } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_transfer_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_transfer_transition/v0/mod.rs index c51f80cdb7..3708794cf7 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_transfer_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_transfer_transition/v0/mod.rs @@ -25,7 +25,7 @@ mod property_names { serde(rename_all = "camelCase") )] #[display( - fmt = "Base: {}, Revision: {}, Recipient: {:?}", + "Base: {}, Revision: {}, Recipient: {:?}", "base", "revision", "recipient_owner_id" diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_update_price_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_update_price_transition/mod.rs index 25a16a09ae..e85c1513db 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_update_price_transition/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_update_price_transition/mod.rs @@ -14,6 +14,6 @@ pub use v0::*; derive(Serialize, Deserialize) )] pub enum DocumentUpdatePriceTransition { - #[display(fmt = "V0({})", "_0")] + #[display("V0({})", "_0")] V0(DocumentUpdatePriceTransitionV0), } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_update_price_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_update_price_transition/v0/mod.rs index fe1e11cae1..8e264bba97 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_update_price_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_update_price_transition/v0/mod.rs @@ -23,7 +23,7 @@ mod property_names { derive(Serialize, Deserialize), serde(rename_all = "camelCase") )] -#[display(fmt = "Base: {}, Revision: {}, Price: {}", "base", "revision", "price")] +#[display("Base: {}, Revision: {}, Price: {}", "base", "revision", "price")] pub struct DocumentUpdatePriceTransitionV0 { #[cfg_attr(feature = "state-transition-serde-conversion", serde(flatten))] pub base: DocumentBaseTransition, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/mod.rs index 00e566b2a8..448dffcfea 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/mod.rs @@ -76,22 +76,22 @@ pub trait DocumentTransitionV0Methods { derive(Serialize, Deserialize) )] pub enum DocumentTransition { - #[display(fmt = "CreateDocumentTransition({})", "_0")] + #[display("CreateDocumentTransition({})", "_0")] Create(DocumentCreateTransition), - #[display(fmt = "ReplaceDocumentTransition({})", "_0")] + #[display("ReplaceDocumentTransition({})", "_0")] Replace(DocumentReplaceTransition), - #[display(fmt = "DeleteDocumentTransition({})", "_0")] + #[display("DeleteDocumentTransition({})", "_0")] Delete(DocumentDeleteTransition), - #[display(fmt = "TransferDocumentTransition({})", "_0")] + #[display("TransferDocumentTransition({})", "_0")] Transfer(DocumentTransferTransition), - #[display(fmt = "UpdatePriceDocumentTransition({})", "_0")] + #[display("UpdatePriceDocumentTransition({})", "_0")] UpdatePrice(DocumentUpdatePriceTransition), - #[display(fmt = "PurchaseDocumentTransition({})", "_0")] + #[display("PurchaseDocumentTransition({})", "_0")] Purchase(DocumentPurchaseTransition), } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_withdrawal_transition/methods/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_withdrawal_transition/methods/v0/mod.rs index d143eaae31..2836b96cc6 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_withdrawal_transition/methods/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_withdrawal_transition/methods/v0/mod.rs @@ -16,12 +16,12 @@ use platform_version::version::{FeatureVersion, PlatformVersion}; pub enum PreferredKeyPurposeForSigningWithdrawal { /// Use any key Any, - /// Use the master key, then the transfer key - MasterPreferred, - /// Use the transfer key, then the master key + /// Use the owner key, then the transfer key + OwnerPreferred, + /// Use the transfer key, then the owner key TransferPreferred, - /// Only use the master key - MasterOnly, + /// Only use the owner key + OwnerOnly, /// Only use the transfer key TransferOnly, } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_withdrawal_transition/v1/identity_signed.rs b/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_withdrawal_transition/v1/identity_signed.rs index 045bab7b27..bc541c4b3c 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_withdrawal_transition/v1/identity_signed.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_withdrawal_transition/v1/identity_signed.rs @@ -1,4 +1,4 @@ -use crate::identity::SecurityLevel::{CRITICAL, MASTER}; +use crate::identity::SecurityLevel::CRITICAL; use crate::identity::{KeyID, Purpose, SecurityLevel}; use crate::state_transition::identity_credit_withdrawal_transition::v1::IdentityCreditWithdrawalTransitionV1; use crate::state_transition::StateTransitionIdentitySigned; @@ -12,16 +12,12 @@ impl StateTransitionIdentitySigned for IdentityCreditWithdrawalTransitionV1 { self.signature_public_key_id = key_id } - fn security_level_requirement(&self, purpose: Purpose) -> Vec { - if purpose == Purpose::AUTHENTICATION { - vec![MASTER] - } else { - // for transfer - vec![CRITICAL] - } + fn security_level_requirement(&self, _purpose: Purpose) -> Vec { + // critical is used for both transfer and owner + vec![CRITICAL] } fn purpose_requirement(&self) -> Vec { - vec![Purpose::TRANSFER, Purpose::AUTHENTICATION] + vec![Purpose::TRANSFER, Purpose::OWNER] } } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_withdrawal_transition/v1/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_withdrawal_transition/v1/v0_methods.rs index de4817bca4..8f20f27494 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_withdrawal_transition/v1/v0_methods.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_withdrawal_transition/v1/v0_methods.rs @@ -65,9 +65,9 @@ impl IdentityCreditWithdrawalTransitionMethodsV0 for IdentityCreditWithdrawalTra let mut key: Option<&IdentityPublicKey>; match preferred_key_purpose_for_signing_withdrawal { - PreferredKeyPurposeForSigningWithdrawal::MasterPreferred => { + PreferredKeyPurposeForSigningWithdrawal::OwnerPreferred => { key = identity.get_first_public_key_matching( - Purpose::AUTHENTICATION, + Purpose::OWNER, SecurityLevel::full_range().into(), KeyType::all_key_types().into(), true, @@ -93,16 +93,16 @@ impl IdentityCreditWithdrawalTransitionMethodsV0 for IdentityCreditWithdrawalTra if key.is_none() || !signer.can_sign_with(key.unwrap()) { key = identity.get_first_public_key_matching( - Purpose::AUTHENTICATION, + Purpose::OWNER, SecurityLevel::full_range().into(), KeyType::all_key_types().into(), true, ); } } - PreferredKeyPurposeForSigningWithdrawal::MasterOnly => { + PreferredKeyPurposeForSigningWithdrawal::OwnerOnly => { key = identity.get_first_public_key_matching( - Purpose::AUTHENTICATION, + Purpose::OWNER, SecurityLevel::full_range().into(), KeyType::all_key_types().into(), true, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/identity/public_key_in_creation/methods/validate_identity_public_keys_structure/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/identity/public_key_in_creation/methods/validate_identity_public_keys_structure/v0/mod.rs index 81b489092b..6b02b2e645 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/identity/public_key_in_creation/methods/validate_identity_public_keys_structure/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/identity/public_key_in_creation/methods/validate_identity_public_keys_structure/v0/mod.rs @@ -19,7 +19,7 @@ use crate::ProtocolError; use platform_version::version::PlatformVersion; lazy_static! { - static ref ALLOWED_SECURITY_LEVELS: HashMap> = { + static ref ALLOWED_SECURITY_LEVELS_FOR_EXTERNALLY_ADDED_KEYS: HashMap> = { let mut m = HashMap::new(); m.insert( Purpose::AUTHENTICATION, @@ -119,8 +119,8 @@ impl IdentityPublicKeyInCreation { let validation_errors = identity_public_keys_with_witness .iter() .filter_map(|identity_public_key| { - let allowed_security_levels = - ALLOWED_SECURITY_LEVELS.get(&identity_public_key.purpose()); + let allowed_security_levels = ALLOWED_SECURITY_LEVELS_FOR_EXTERNALLY_ADDED_KEYS + .get(&identity_public_key.purpose()); if let Some(levels) = allowed_security_levels { if !levels.contains(&identity_public_key.security_level()) { Some( diff --git a/packages/rs-drive-abci/Cargo.toml b/packages/rs-drive-abci/Cargo.toml index 4e14f953f7..dfcd0e0e25 100644 --- a/packages/rs-drive-abci/Cargo.toml +++ b/packages/rs-drive-abci/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "drive-abci" -version = "1.4.0-dev.3" +version = "1.4.1" authors = [ "Samuel Westrich ", "Ivan Shumkov ", @@ -33,8 +33,8 @@ dpp = { path = "../rs-dpp", features = ["abci"] } simple-signer = { path = "../simple-signer" } rust_decimal = "1.2.5" rust_decimal_macros = "1.25.0" -mockall = { version = "0.11", optional = true } -prost = { version = "0.12", default-features = false } +mockall = { version = "0.13", optional = true } +prost = { version = "0.13", default-features = false } tracing = { version = "0.1.37", default-features = false, features = [] } clap = { version = "4.4.10", features = ["derive"] } envy = { version = "0.4.2" } @@ -49,30 +49,31 @@ tracing-subscriber = { version = "0.3.16", default-features = false, features = "registry", "tracing-log", ], optional = false } -atty = { version = "0.2.14", optional = false } -tenderdash-abci = { git = "https://github.com/dashpay/rs-tenderdash-abci", version = "1.2.0+1.3.0", tag = "v1.2.0+1.3.0", features = [ +tenderdash-abci = { git = "https://github.com/dashpay/rs-tenderdash-abci", version = "1.2.1", tag = "v1.2.1+1.3.0", features = [ "grpc", ] } lazy_static = "1.4.0" -itertools = { version = "0.10.5" } +itertools = { version = "0.13" } file-rotate = { version = "0.7.3" } reopen = { version = "1.0.3" } -delegate = { version = "0.9.0" } +delegate = { version = "0.13" } regex = { version = "1.8.1" } -metrics = { version = "0.22.3" } -metrics-exporter-prometheus = { version = "0.14.0" } +metrics = { version = "0.23" } +metrics-exporter-prometheus = { version = "0.15", default-features = false, features = [ + "http-listener", +] } url = { version = "2.3.1" } ureq = { "version" = "2.6.2" } -tokio = { version = "1.36", features = [ +tokio = { version = "1.40", features = [ "macros", "signal", "rt-multi-thread", "time", ] } -tokio-util = { version = "0.7.8" } -derive_more = "0.99.17" +tokio-util = { version = "0.7" } +derive_more = { version = "1.0", features = ["from", "deref", "deref_mut"] } async-trait = "0.1.77" -console-subscriber = { version = "0.2.0", optional = true } +console-subscriber = { version = "0.4", optional = true } [dev-dependencies] bs58 = { version = "0.5.0" } diff --git a/packages/rs-drive-abci/src/config.rs b/packages/rs-drive-abci/src/config.rs index 8e8f449aac..1e8f5f3c26 100644 --- a/packages/rs-drive-abci/src/config.rs +++ b/packages/rs-drive-abci/src/config.rs @@ -180,9 +180,6 @@ pub struct PlatformConfig { /// Approximately how often are blocks produced pub block_spacing_ms: u64, - /// Initial protocol version - pub initial_protocol_version: ProtocolVersion, - /// Path to data storage pub db_path: PathBuf, @@ -276,7 +273,6 @@ impl<'de> Deserialize<'de> for PlatformConfig { chain_lock: config.chain_lock, instant_lock: config.instant_lock, block_spacing_ms: config.block_spacing_ms, - initial_protocol_version: config.initial_protocol_version, db_path: config.db_path, rejections_path: config.rejections_path, #[cfg(feature = "testing-config")] @@ -734,7 +730,6 @@ impl PlatformConfig { tokio_console_enabled: false, tokio_console_address: PlatformConfig::default_tokio_console_address(), tokio_console_retention_secs: PlatformConfig::default_tokio_console_retention_secs(), - initial_protocol_version: Self::default_initial_protocol_version(), prometheus_bind_address: None, grpc_bind_address: "127.0.0.1:26670".to_string(), } @@ -777,7 +772,6 @@ impl PlatformConfig { tokio_console_enabled: false, tokio_console_address: PlatformConfig::default_tokio_console_address(), tokio_console_retention_secs: PlatformConfig::default_tokio_console_retention_secs(), - initial_protocol_version: Self::default_initial_protocol_version(), prometheus_bind_address: None, grpc_bind_address: "127.0.0.1:26670".to_string(), } @@ -817,7 +811,6 @@ impl PlatformConfig { rejections_path: Some(PathBuf::from("/var/log/dash/rejected")), #[cfg(feature = "testing-config")] testing_configs: PlatformTestConfig::default(), - initial_protocol_version: Self::default_initial_protocol_version(), prometheus_bind_address: None, grpc_bind_address: "127.0.0.1:26670".to_string(), tokio_console_enabled: false, @@ -860,7 +853,6 @@ impl PlatformConfig { rejections_path: Some(PathBuf::from("/var/log/dash/rejected")), #[cfg(feature = "testing-config")] testing_configs: PlatformTestConfig::default(), - initial_protocol_version: Self::default_initial_protocol_version(), prometheus_bind_address: None, grpc_bind_address: "127.0.0.1:26670".to_string(), tokio_console_enabled: false, diff --git a/packages/rs-drive-abci/src/execution/engine/consensus_params_update/mod.rs b/packages/rs-drive-abci/src/execution/engine/consensus_params_update/mod.rs index 16319d7746..e3163039f1 100644 --- a/packages/rs-drive-abci/src/execution/engine/consensus_params_update/mod.rs +++ b/packages/rs-drive-abci/src/execution/engine/consensus_params_update/mod.rs @@ -7,6 +7,8 @@ use dpp::version::PlatformVersion; use tenderdash_abci::proto::types::ConsensusParams; mod v0; +mod v1; + pub(crate) fn consensus_params_update( network: Network, original_platform_version: &PlatformVersion, @@ -25,9 +27,15 @@ pub(crate) fn consensus_params_update( new_platform_version, epoch_info, )), + 1 => Ok(v1::consensus_params_update_v1( + network, + original_platform_version, + new_platform_version, + epoch_info, + )), version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { method: "consensus_params_update".to_string(), - known_versions: vec![0], + known_versions: vec![0, 1], received: version, })), } diff --git a/packages/rs-drive-abci/src/execution/engine/consensus_params_update/v1/mod.rs b/packages/rs-drive-abci/src/execution/engine/consensus_params_update/v1/mod.rs new file mode 100644 index 0000000000..85e9d40180 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/engine/consensus_params_update/v1/mod.rs @@ -0,0 +1,74 @@ +use crate::platform_types::epoch_info::v0::EpochInfoV0Methods; +use crate::platform_types::epoch_info::EpochInfo; +use dpp::dashcore::Network; +use dpp::version::PlatformVersion; +use tenderdash_abci::proto::types::{ConsensusParams, VersionParams}; + +#[inline(always)] +pub(super) fn consensus_params_update_v1( + network: Network, + original_platform_version: &PlatformVersion, + new_platform_version: &PlatformVersion, + epoch_info: &EpochInfo, +) -> Option { + // These are emergency consensus updates + match network { + Network::Dash => { + if epoch_info.is_first_block_of_epoch(3) { + return Some(ConsensusParams { + block: None, + evidence: None, + validator: None, + version: Some(VersionParams { + app_version: new_platform_version.protocol_version as u64, + consensus_version: 1, + }), + synchrony: None, + timeout: None, + abci: None, + }); + } + } + Network::Testnet => { + if epoch_info.is_first_block_of_epoch(1480) { + return Some(ConsensusParams { + block: None, + evidence: None, + validator: None, + version: Some(VersionParams { + app_version: new_platform_version.protocol_version as u64, + consensus_version: 1, + }), + synchrony: None, + timeout: None, + abci: None, + }); + } + } + _ => {} + } + + // Update versions if any of them changed + if original_platform_version + .consensus + .tenderdash_consensus_version + == new_platform_version.consensus.tenderdash_consensus_version + && original_platform_version.protocol_version == new_platform_version.protocol_version + { + None + } else { + Some(ConsensusParams { + block: None, + evidence: None, + validator: None, + version: Some(VersionParams { + app_version: new_platform_version.protocol_version as u64, + consensus_version: new_platform_version.consensus.tenderdash_consensus_version + as i32, + }), + synchrony: None, + timeout: None, + abci: None, + }) + } +} diff --git a/packages/rs-drive-abci/src/execution/engine/initialization/init_chain/mod.rs b/packages/rs-drive-abci/src/execution/engine/initialization/init_chain/mod.rs index 57ec814c04..1b580ba38d 100644 --- a/packages/rs-drive-abci/src/execution/engine/initialization/init_chain/mod.rs +++ b/packages/rs-drive-abci/src/execution/engine/initialization/init_chain/mod.rs @@ -5,8 +5,10 @@ use crate::platform_types::platform::Platform; use crate::rpc::core::CoreRPCLike; +use crate::abci::AbciError; use crate::error::execution::ExecutionError; use dpp::version::PlatformVersion; +use dpp::version::ProtocolVersion; use drive::grovedb::Transaction; use tenderdash_abci::proto::abci::{RequestInitChain, ResponseInitChain}; @@ -22,8 +24,31 @@ where ) -> Result { // We don't have platform state at this point, so we should // use initial protocol version from genesis - let protocol_version = self.config.initial_protocol_version; - let platform_version = PlatformVersion::get(protocol_version)?; + let consensus_params = request + .consensus_params + .as_ref() + .ok_or(AbciError::BadRequest( + "consensus params are required in init chain".to_string(), + ))?; + + let tenderdash_abci::proto::types::VersionParams { + app_version: protocol_version, + .. + } = consensus_params + .version + .as_ref() + .ok_or(AbciError::BadRequest( + "consensus params version is required in init chain".to_string(), + ))?; + + let platform_version = if *protocol_version == 0 { + // Protocol version is not set. + // We are starting the chain with the desired version + PlatformVersion::desired() + } else { + // Use the version from the genesis + PlatformVersion::get(*protocol_version as ProtocolVersion)? + }; match platform_version.drive_abci.methods.engine.init_chain { 0 => self.init_chain_v0(request, transaction, platform_version), diff --git a/packages/rs-drive-abci/src/execution/engine/initialization/init_chain/v0/mod.rs b/packages/rs-drive-abci/src/execution/engine/initialization/init_chain/v0/mod.rs index 3d0bc673a1..b67cd01253 100644 --- a/packages/rs-drive-abci/src/execution/engine/initialization/init_chain/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/engine/initialization/init_chain/v0/mod.rs @@ -7,7 +7,10 @@ use dpp::block::block_info::BlockInfo; use drive::error::Error::GroveDB; use drive::grovedb::Transaction; +use crate::execution::engine::consensus_params_update::consensus_params_update; use crate::platform_types::cleaned_abci_messages::request_init_chain_cleaned_params; +use crate::platform_types::epoch_info::v0::EpochInfoV0; +use crate::platform_types::epoch_info::EpochInfo; use crate::platform_types::platform_state::v0::PlatformStateV0Methods; use crate::platform_types::platform_state::PlatformState; use crate::platform_types::validator_set::ValidatorSetExt; @@ -68,8 +71,8 @@ where // Create platform execution state let mut initial_platform_state = PlatformState::default_with_protocol_versions( - request.initial_protocol_version, - request.initial_protocol_version, + platform_version.protocol_version, + platform_version.protocol_version, &self.config, )?; @@ -113,9 +116,6 @@ where initial_platform_state.set_genesis_block_info(Some(genesis_block_info)); - initial_platform_state - .set_current_protocol_version_in_consensus(request.initial_protocol_version); - if tracing::enabled!(tracing::Level::TRACE) { tracing::trace!( platform_state_fingerprint = hex::encode(initial_platform_state.fingerprint()?), @@ -132,8 +132,24 @@ where .unwrap() .map_err(GroveDB)?; + // We use first platform version because Tenderdash starts genesis with first versions + // by default + let first_platform_version = PlatformVersion::first(); + + let epoch_info = EpochInfo::V0(EpochInfoV0::calculate( + genesis_time, + genesis_time, + None, + self.config.execution.epoch_time_length_s, + )?); + Ok(ResponseInitChain { - consensus_params: None, + consensus_params: consensus_params_update( + self.config.network, + first_platform_version, + platform_version, + &epoch_info, + )?, app_hash: app_hash.to_vec(), validator_set_update: Some(validator_set), next_core_chain_lock_update: None, diff --git a/packages/rs-drive-abci/src/execution/engine/run_block_proposal/mod.rs b/packages/rs-drive-abci/src/execution/engine/run_block_proposal/mod.rs index e2149678b3..43712c7feb 100644 --- a/packages/rs-drive-abci/src/execution/engine/run_block_proposal/mod.rs +++ b/packages/rs-drive-abci/src/execution/engine/run_block_proposal/mod.rs @@ -1,12 +1,15 @@ use crate::error::execution::ExecutionError; use crate::error::Error; +use crate::execution::types::block_state_info; +use crate::execution::types::block_state_info::v0::BlockStateInfoV0Methods; use crate::metrics::HistogramTiming; -use crate::platform_types::epoch_info::v0::EpochInfoV0Methods; +use crate::platform_types::epoch_info::v0::{EpochInfoV0Getters, EpochInfoV0Methods}; use crate::platform_types::platform::Platform; use crate::platform_types::platform_state::v0::PlatformStateV0Methods; use crate::platform_types::platform_state::PlatformState; use crate::platform_types::{block_execution_outcome, block_proposal}; use crate::rpc::core::CoreRPCLike; +use dpp::block::epoch::Epoch; use dpp::validation::ValidationResult; use dpp::version::PlatformVersion; use drive::grovedb::Transaction; @@ -97,8 +100,24 @@ Your software version: {}, latest supported protocol version: {}."#, // Set current protocol version to the block platform state block_platform_state .set_current_protocol_version_in_consensus(next_protocol_version); + + let last_block_time_ms = platform_state.last_committed_block_time_ms(); + + // Init block execution context + let block_state_info = block_state_info::v0::BlockStateInfoV0::from_block_proposal( + &block_proposal, + last_block_time_ms, + ); + + let block_info = block_state_info.to_block_info( + Epoch::new(epoch_info.current_epoch_index()) + .expect("current epoch index should be in range"), + ); + // This is for events like adding stuff to the root tree, or making structural changes/fixes self.perform_events_on_first_block_of_protocol_change( + platform_state, + &block_info, transaction, old_protocol_version, next_platform_version, diff --git a/packages/rs-drive-abci/src/execution/platform_events/block_fee_processing/tests.rs b/packages/rs-drive-abci/src/execution/platform_events/block_fee_processing/tests.rs index fcbf1e8314..1cbac74c74 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/block_fee_processing/tests.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/block_fee_processing/tests.rs @@ -795,7 +795,7 @@ mod refund_tests { platform_state .previous_fee_versions_mut() - .insert(5, platform_version_with_higher_fees.fee_version.clone()); + .insert(5, platform_version_with_higher_fees.fee_version.as_static()); let (mut fee_results, _) = process_state_transitions( &platform, diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/create_owner_identity/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/create_owner_identity/mod.rs index 042b35c5ca..048ea1266a 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/create_owner_identity/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/create_owner_identity/mod.rs @@ -1,4 +1,5 @@ mod v0; +mod v1; use crate::error::execution::ExecutionError; use crate::error::Error; @@ -38,9 +39,10 @@ where .create_owner_identity { 0 => Self::create_owner_identity_v0(masternode, platform_version), + 1 => Self::create_owner_identity_v1(masternode, platform_version), version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { method: "create_owner_identity".to_string(), - known_versions: vec![0], + known_versions: vec![0, 1], received: version, })), } diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/create_owner_identity/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/create_owner_identity/v0/mod.rs index 18028f7a31..176b6d90db 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/create_owner_identity/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/create_owner_identity/v0/mod.rs @@ -25,7 +25,9 @@ where Ok(identity) } - fn get_owner_identifier(masternode: &MasternodeListItem) -> Result { + pub(crate) fn get_owner_identifier( + masternode: &MasternodeListItem, + ) -> Result { let masternode_identifier: [u8; 32] = masternode.pro_tx_hash.into(); Ok(masternode_identifier.into()) } diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/create_owner_identity/v1/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/create_owner_identity/v1/mod.rs new file mode 100644 index 0000000000..da89aaafc7 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/create_owner_identity/v1/mod.rs @@ -0,0 +1,33 @@ +use crate::error::Error; +use crate::platform_types::platform::Platform; +use crate::rpc::core::CoreRPCLike; +use dashcore_rpc::dashcore_rpc_json::MasternodeListItem; +use dpp::identity::accessors::IdentityGettersV0; +use dpp::identity::Identity; +use dpp::version::PlatformVersion; + +impl Platform +where + C: CoreRPCLike, +{ + pub(super) fn create_owner_identity_v1( + masternode: &MasternodeListItem, + platform_version: &PlatformVersion, + ) -> Result { + let owner_identifier = Self::get_owner_identifier(masternode)?; + let mut identity = Identity::create_basic_identity(owner_identifier, platform_version)?; + identity.add_public_keys([ + Self::get_owner_identity_withdrawal_key( + masternode.state.payout_address, + 0, + platform_version, + )?, + Self::get_owner_identity_owner_key( + masternode.state.owner_address, + 1, + platform_version, + )?, + ]); + Ok(identity) + } +} diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/get_owner_identity_owner_key/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/get_owner_identity_owner_key/mod.rs new file mode 100644 index 0000000000..8b76f02566 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/get_owner_identity_owner_key/mod.rs @@ -0,0 +1,45 @@ +mod v0; + +use crate::error::execution::ExecutionError; +use crate::error::Error; +use crate::platform_types::platform::Platform; + +use dpp::identity::{IdentityPublicKey, KeyID}; + +use dpp::version::PlatformVersion; + +impl Platform { + /// Retrieves an identity public key using the provided owner key and key ID. + /// + /// This function derives the identity public key and delegates to a version-specific method depending on the platform version. + /// + /// # Arguments + /// + /// * owner_public_key_address - The public key address of the owner. + /// * key_id - The KeyID for the identity public key. + /// * platform_version - The version of the platform to determine which method to delegate to. + /// + /// # Returns + /// + /// * Result - Returns the derived identity public key if successful. Otherwise, returns an error. + pub(crate) fn get_owner_identity_owner_key( + owner_public_key_address: [u8; 20], + key_id: KeyID, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .drive_abci + .methods + .core_based_updates + .masternode_updates + .get_owner_identity_owner_key + { + 0 => Self::get_owner_identity_owner_key_v0(owner_public_key_address, key_id), + version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { + method: "get_owner_identity_owner_key".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/get_owner_identity_owner_key/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/get_owner_identity_owner_key/v0/mod.rs new file mode 100644 index 0000000000..ba099e99ed --- /dev/null +++ b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/get_owner_identity_owner_key/v0/mod.rs @@ -0,0 +1,24 @@ +use crate::error::Error; +use crate::platform_types::platform::Platform; +use dpp::identity::identity_public_key::v0::IdentityPublicKeyV0; +use dpp::identity::{IdentityPublicKey, KeyID, KeyType, Purpose, SecurityLevel}; +use dpp::platform_value::BinaryData; + +impl Platform { + pub(super) fn get_owner_identity_owner_key_v0( + owner_public_key_address: [u8; 20], + key_id: KeyID, + ) -> Result { + Ok(IdentityPublicKeyV0 { + id: key_id, + key_type: KeyType::ECDSA_HASH160, + purpose: Purpose::OWNER, + security_level: SecurityLevel::CRITICAL, + read_only: true, + data: BinaryData::new(owner_public_key_address.to_vec()), + disabled_at: None, + contract_bounds: None, + } + .into()) + } +} diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/get_owner_identity_key/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/get_owner_identity_withdrawal_key/mod.rs similarity index 100% rename from packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/get_owner_identity_key/mod.rs rename to packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/get_owner_identity_withdrawal_key/mod.rs diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/get_owner_identity_key/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/get_owner_identity_withdrawal_key/v0/mod.rs similarity index 100% rename from packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/get_owner_identity_key/v0/mod.rs rename to packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/get_owner_identity_withdrawal_key/v0/mod.rs diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/mod.rs index e3168a64e7..e2a9176d3c 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/mod.rs @@ -4,14 +4,14 @@ mod create_voter_identity; mod disable_identity_keys; mod get_operator_identifier; mod get_operator_identity_keys; -mod get_owner_identity_key; +mod get_owner_identity_owner_key; +mod get_owner_identity_withdrawal_key; mod get_voter_identifier; mod get_voter_identity_key; mod update_masternode_identities; mod update_operator_identity; mod update_owner_withdrawal_address; mod update_voter_identity; - // // // #[cfg(test)] diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/update_owner_withdrawal_address/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/update_owner_withdrawal_address/mod.rs index f2f5b5c708..1f81d17c0b 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/update_owner_withdrawal_address/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/update_owner_withdrawal_address/mod.rs @@ -11,6 +11,7 @@ use drive::util::batch::DriveOperation; use drive::grovedb::Transaction; mod v0; +mod v1; impl Platform where @@ -61,11 +62,286 @@ where drive_operations, platform_version, ), + 1 => self.update_owner_withdrawal_address_v1( + owner_identifier, + new_withdrawal_address, + block_info, + transaction, + drive_operations, + platform_version, + ), version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { method: "update_owner_withdrawal_address".to_string(), - known_versions: vec![0], + known_versions: vec![0, 1], received: version, })), } } } + +#[cfg(test)] +mod tests { + use crate::test::helpers::setup::TestPlatformBuilder; + use dpp::block::block_info::BlockInfo; + use dpp::identity::accessors::IdentityGettersV0; + use dpp::identity::identity_public_key::v0::IdentityPublicKeyV0; + use dpp::identity::{Identity, IdentityV0, KeyType, Purpose, SecurityLevel}; + use dpp::platform_value::BinaryData; + use dpp::prelude::{Identifier, IdentityPublicKey}; + use platform_version::version::PlatformVersion; + use rand::prelude::StdRng; + use rand::Rng; + use rand::SeedableRng; + use std::collections::BTreeMap; + + #[test] + fn test_update_withdrawal_address() { + let platform_version = PlatformVersion::latest(); + let platform = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_genesis_state(); + + let block_info = BlockInfo::default(); + + let mut rng = StdRng::seed_from_u64(5); + + let payout_address: [u8; 20] = rng.gen(); + + let withdrawal_key: IdentityPublicKey = IdentityPublicKeyV0 { + id: 0, + key_type: KeyType::ECDSA_HASH160, + purpose: Purpose::TRANSFER, + security_level: SecurityLevel::CRITICAL, + read_only: true, + data: BinaryData::new(payout_address.to_vec()), + disabled_at: None, + contract_bounds: None, + } + .into(); + + let identity: Identity = IdentityV0 { + id: Identifier::random_with_rng(&mut rng), + public_keys: BTreeMap::from([(0, withdrawal_key.clone())]), + balance: 0, + revision: 0, + } + .into(); + + // We just add this identity to the system first + + platform + .drive + .add_new_identity( + identity.clone(), + true, + &block_info, + true, + None, + platform_version, + ) + .expect("expected to add a new identity"); + + let transaction = platform.drive.grove.start_transaction(); + + let mut drive_operations = vec![]; + + platform + .update_owner_withdrawal_address( + identity.id().to_buffer(), + [0; 20], + &block_info, + &transaction, + &mut drive_operations, + platform_version, + ) + .expect("expected to update owner withdrawal address"); + + platform + .drive + .apply_drive_operations( + drive_operations, + true, + &block_info, + Some(&transaction), + platform_version, + None, + ) + .expect("expected to apply drive operations"); + } + + #[test] + fn test_update_to_same_withdrawal_address() { + let platform_version = PlatformVersion::latest(); + let platform = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_genesis_state(); + + let block_info = BlockInfo::default(); + + let mut rng = StdRng::seed_from_u64(5); + + let payout_address: [u8; 20] = rng.gen(); + + let withdrawal_key: IdentityPublicKey = IdentityPublicKeyV0 { + id: 0, + key_type: KeyType::ECDSA_HASH160, + purpose: Purpose::TRANSFER, + security_level: SecurityLevel::CRITICAL, + read_only: true, + data: BinaryData::new(payout_address.to_vec()), + disabled_at: None, + contract_bounds: None, + } + .into(); + + let identity: Identity = IdentityV0 { + id: Identifier::random_with_rng(&mut rng), + public_keys: BTreeMap::from([(0, withdrawal_key.clone())]), + balance: 0, + revision: 0, + } + .into(); + + // We just add this identity to the system first + + platform + .drive + .add_new_identity( + identity.clone(), + true, + &block_info, + true, + None, + platform_version, + ) + .expect("expected to add a new identity"); + + let transaction = platform.drive.grove.start_transaction(); + + let mut drive_operations = vec![]; + + platform + .update_owner_withdrawal_address( + identity.id().to_buffer(), + payout_address, + &block_info, + &transaction, + &mut drive_operations, + platform_version, + ) + .expect("expected to update owner withdrawal address"); + + platform + .drive + .apply_drive_operations( + drive_operations, + true, + &block_info, + Some(&transaction), + platform_version, + None, + ) + .expect("expected to apply drive operations"); + } + #[test] + fn test_update_to_previously_disabled_withdrawal_address() { + let platform_version = PlatformVersion::latest(); + let platform = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_genesis_state(); + + let block_info = BlockInfo::default(); + + let mut rng = StdRng::seed_from_u64(5); + + let payout_address: [u8; 20] = rng.gen(); + + let withdrawal_key: IdentityPublicKey = IdentityPublicKeyV0 { + id: 0, + key_type: KeyType::ECDSA_HASH160, + purpose: Purpose::TRANSFER, + security_level: SecurityLevel::CRITICAL, + read_only: true, + data: BinaryData::new(payout_address.to_vec()), + disabled_at: None, + contract_bounds: None, + } + .into(); + + let identity: Identity = IdentityV0 { + id: Identifier::random_with_rng(&mut rng), + public_keys: BTreeMap::from([(0, withdrawal_key.clone())]), + balance: 0, + revision: 0, + } + .into(); + + // We just add this identity to the system first + + platform + .drive + .add_new_identity( + identity.clone(), + true, + &block_info, + true, + None, + platform_version, + ) + .expect("expected to add a new identity"); + + let transaction = platform.drive.grove.start_transaction(); + + let mut drive_operations = vec![]; + + platform + .update_owner_withdrawal_address( + identity.id().to_buffer(), + [0; 20], + &block_info, + &transaction, + &mut drive_operations, + platform_version, + ) + .expect("expected to update owner withdrawal address"); + + platform + .drive + .apply_drive_operations( + drive_operations, + true, + &block_info, + Some(&transaction), + platform_version, + None, + ) + .expect("expected to apply drive operations"); + + let transaction = platform.drive.grove.start_transaction(); + + let mut drive_operations = vec![]; + + platform + .update_owner_withdrawal_address( + identity.id().to_buffer(), + payout_address, + &block_info, + &transaction, + &mut drive_operations, + platform_version, + ) + .expect("expected to update owner withdrawal address"); + + platform + .drive + .apply_drive_operations( + drive_operations, + true, + &block_info, + Some(&transaction), + platform_version, + None, + ) + .expect("expected to apply drive operations"); + } +} diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/update_owner_withdrawal_address/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/update_owner_withdrawal_address/v0/mod.rs index 8484f4436d..640a038160 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/update_owner_withdrawal_address/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/update_owner_withdrawal_address/v0/mod.rs @@ -124,270 +124,3 @@ where Ok(()) } } - -#[cfg(test)] -mod tests { - use crate::test::helpers::setup::TestPlatformBuilder; - use dpp::block::block_info::BlockInfo; - use dpp::identity::accessors::IdentityGettersV0; - use dpp::identity::identity_public_key::v0::IdentityPublicKeyV0; - use dpp::identity::{Identity, IdentityV0, KeyType, Purpose, SecurityLevel}; - use dpp::platform_value::BinaryData; - use dpp::prelude::{Identifier, IdentityPublicKey}; - use platform_version::version::PlatformVersion; - use rand::prelude::StdRng; - use rand::Rng; - use rand::SeedableRng; - use std::collections::BTreeMap; - - #[test] - fn test_update_withdrawal_address() { - let platform_version = PlatformVersion::latest(); - let platform = TestPlatformBuilder::new() - .build_with_mock_rpc() - .set_genesis_state(); - - let block_info = BlockInfo::default(); - - let mut rng = StdRng::seed_from_u64(5); - - let payout_address: [u8; 20] = rng.gen(); - - let withdrawal_key: IdentityPublicKey = IdentityPublicKeyV0 { - id: 0, - key_type: KeyType::ECDSA_HASH160, - purpose: Purpose::TRANSFER, - security_level: SecurityLevel::CRITICAL, - read_only: true, - data: BinaryData::new(payout_address.to_vec()), - disabled_at: None, - contract_bounds: None, - } - .into(); - - let identity: Identity = IdentityV0 { - id: Identifier::random_with_rng(&mut rng), - public_keys: BTreeMap::from([(0, withdrawal_key.clone())]), - balance: 0, - revision: 0, - } - .into(); - - // We just add this identity to the system first - - platform - .drive - .add_new_identity( - identity.clone(), - true, - &block_info, - true, - None, - platform_version, - ) - .expect("expected to add a new identity"); - - let transaction = platform.drive.grove.start_transaction(); - - let mut drive_operations = vec![]; - - platform - .update_owner_withdrawal_address( - identity.id().to_buffer(), - [0; 20], - &block_info, - &transaction, - &mut drive_operations, - platform_version, - ) - .expect("expected to update owner withdrawal address"); - - platform - .drive - .apply_drive_operations( - drive_operations, - true, - &block_info, - Some(&transaction), - platform_version, - None, - ) - .expect("expected to apply drive operations"); - } - - #[test] - fn test_update_to_same_withdrawal_address() { - let platform_version = PlatformVersion::latest(); - let platform = TestPlatformBuilder::new() - .build_with_mock_rpc() - .set_genesis_state(); - - let block_info = BlockInfo::default(); - - let mut rng = StdRng::seed_from_u64(5); - - let payout_address: [u8; 20] = rng.gen(); - - let withdrawal_key: IdentityPublicKey = IdentityPublicKeyV0 { - id: 0, - key_type: KeyType::ECDSA_HASH160, - purpose: Purpose::TRANSFER, - security_level: SecurityLevel::CRITICAL, - read_only: true, - data: BinaryData::new(payout_address.to_vec()), - disabled_at: None, - contract_bounds: None, - } - .into(); - - let identity: Identity = IdentityV0 { - id: Identifier::random_with_rng(&mut rng), - public_keys: BTreeMap::from([(0, withdrawal_key.clone())]), - balance: 0, - revision: 0, - } - .into(); - - // We just add this identity to the system first - - platform - .drive - .add_new_identity( - identity.clone(), - true, - &block_info, - true, - None, - platform_version, - ) - .expect("expected to add a new identity"); - - let transaction = platform.drive.grove.start_transaction(); - - let mut drive_operations = vec![]; - - platform - .update_owner_withdrawal_address( - identity.id().to_buffer(), - payout_address, - &block_info, - &transaction, - &mut drive_operations, - platform_version, - ) - .expect("expected to update owner withdrawal address"); - - platform - .drive - .apply_drive_operations( - drive_operations, - true, - &block_info, - Some(&transaction), - platform_version, - None, - ) - .expect("expected to apply drive operations"); - } - #[test] - fn test_update_to_previously_disabled_withdrawal_address() { - let platform_version = PlatformVersion::latest(); - let platform = TestPlatformBuilder::new() - .build_with_mock_rpc() - .set_genesis_state(); - - let block_info = BlockInfo::default(); - - let mut rng = StdRng::seed_from_u64(5); - - let payout_address: [u8; 20] = rng.gen(); - - let withdrawal_key: IdentityPublicKey = IdentityPublicKeyV0 { - id: 0, - key_type: KeyType::ECDSA_HASH160, - purpose: Purpose::TRANSFER, - security_level: SecurityLevel::CRITICAL, - read_only: true, - data: BinaryData::new(payout_address.to_vec()), - disabled_at: None, - contract_bounds: None, - } - .into(); - - let identity: Identity = IdentityV0 { - id: Identifier::random_with_rng(&mut rng), - public_keys: BTreeMap::from([(0, withdrawal_key.clone())]), - balance: 0, - revision: 0, - } - .into(); - - // We just add this identity to the system first - - platform - .drive - .add_new_identity( - identity.clone(), - true, - &block_info, - true, - None, - platform_version, - ) - .expect("expected to add a new identity"); - - let transaction = platform.drive.grove.start_transaction(); - - let mut drive_operations = vec![]; - - platform - .update_owner_withdrawal_address( - identity.id().to_buffer(), - [0; 20], - &block_info, - &transaction, - &mut drive_operations, - platform_version, - ) - .expect("expected to update owner withdrawal address"); - - platform - .drive - .apply_drive_operations( - drive_operations, - true, - &block_info, - Some(&transaction), - platform_version, - None, - ) - .expect("expected to apply drive operations"); - - let transaction = platform.drive.grove.start_transaction(); - - let mut drive_operations = vec![]; - - platform - .update_owner_withdrawal_address( - identity.id().to_buffer(), - payout_address, - &block_info, - &transaction, - &mut drive_operations, - platform_version, - ) - .expect("expected to update owner withdrawal address"); - - platform - .drive - .apply_drive_operations( - drive_operations, - true, - &block_info, - Some(&transaction), - platform_version, - None, - ) - .expect("expected to apply drive operations"); - } -} diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/update_owner_withdrawal_address/v1/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/update_owner_withdrawal_address/v1/mod.rs new file mode 100644 index 0000000000..40e074193a --- /dev/null +++ b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/update_owner_withdrawal_address/v1/mod.rs @@ -0,0 +1,136 @@ +use crate::error::execution::ExecutionError; +use crate::error::Error; +use crate::platform_types::platform::Platform; + +use crate::rpc::core::CoreRPCLike; +use dpp::block::block_info::BlockInfo; + +use dpp::identity::identity_public_key::accessors::v0::IdentityPublicKeyGettersV0; +use dpp::identity::{KeyID, Purpose}; + +use dpp::version::PlatformVersion; +use drive::drive::identity::key::fetch::{ + IdentityKeysRequest, KeyIDIdentityPublicKeyPairBTreeMap, KeyRequestType, +}; +use drive::grovedb::Transaction; +use drive::util::batch::DriveOperation; +use drive::util::batch::DriveOperation::IdentityOperation; +use drive::util::batch::IdentityOperationType::{ + AddNewKeysToIdentity, DisableIdentityKeys, ReEnableIdentityKeys, +}; +impl Platform +where + C: CoreRPCLike, +{ + /// In this version we change how the new key_id is found, as there might also be an owner key + pub(super) fn update_owner_withdrawal_address_v1( + &self, + owner_identifier: [u8; 32], + new_withdrawal_address: [u8; 20], + block_info: &BlockInfo, + transaction: &Transaction, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + let key_request = IdentityKeysRequest { + identity_id: owner_identifier, + request_type: KeyRequestType::AllKeys, + limit: None, + offset: None, + }; + + let old_withdrawal_identity_keys = self + .drive + .fetch_identity_keys::( + key_request, + Some(transaction), + platform_version, + )?; + + if old_withdrawal_identity_keys.is_empty() { + return Err(Error::Execution(ExecutionError::DriveMissingData( + "expected masternode owner identity to be in state".to_string(), + ))); + } + + let key_ids_to_disable: Vec = old_withdrawal_identity_keys + .iter() + .filter_map(|(key_id, key)| { + if key.disabled_at().is_some() + || key.data().as_slice() == &new_withdrawal_address + || key.purpose() == Purpose::OWNER + { + // We should not disable the owner key + // Also no need to disable withdrawal keys again + // Or if we are adding the same key we already had + None + } else { + Some(*key_id) + } + }) + .collect(); + + if !key_ids_to_disable.is_empty() { + tracing::trace!( + identity_id = ?owner_identifier, + keys_ids = ?key_ids_to_disable, + disable_at = ?block_info.time_ms, + method = "update_owner_withdrawal_address_v1", + "disable old withdrawal keys in owner identity" + ); + + drive_operations.push(IdentityOperation(DisableIdentityKeys { + identity_id: owner_identifier, + keys_ids: key_ids_to_disable, + })); + } + + if let Some((key_id, previously_disabled_old_key)) = old_withdrawal_identity_keys + .iter() + .find(|(_, key)| key.data().as_slice() == new_withdrawal_address) + { + // there might be a situation where we should do nothing as well + if previously_disabled_old_key.is_disabled() { + // We need to re-enable the withdrawal key + tracing::trace!( + identity_id = ?owner_identifier, + withdrawal_key = ?previously_disabled_old_key, + method = "update_owner_withdrawal_address_v0", + "re-enabled withdrawal key to owner identity" + ); + + drive_operations.push(IdentityOperation(ReEnableIdentityKeys { + identity_id: owner_identifier, + keys_ids: vec![*key_id], + })); + } + } else { + let last_key_id = *old_withdrawal_identity_keys + .keys() + .max() + .expect("there must be keys, we already checked"); + + // add the new key + let new_owner_withdrawal_key = Self::get_owner_identity_withdrawal_key( + new_withdrawal_address, + last_key_id + 1, + platform_version, + )?; + + tracing::trace!( + identity_id = ?owner_identifier, + withdrawal_key = ?new_owner_withdrawal_key, + method = "update_owner_withdrawal_address_v1", + "add new withdrawal key to owner identity" + ); + + drive_operations.push(IdentityOperation(AddNewKeysToIdentity { + identity_id: owner_identifier, + unique_keys_to_add: vec![], + non_unique_keys_to_add: vec![new_owner_withdrawal_key], + })); + } + + Ok(()) + } +} diff --git a/packages/rs-drive-abci/src/execution/platform_events/protocol_upgrade/perform_events_on_first_block_of_protocol_change/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/protocol_upgrade/perform_events_on_first_block_of_protocol_change/mod.rs index 659a7e94aa..56c1e17c6a 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/protocol_upgrade/perform_events_on_first_block_of_protocol_change/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/protocol_upgrade/perform_events_on_first_block_of_protocol_change/mod.rs @@ -3,6 +3,8 @@ mod v0; use crate::error::execution::ExecutionError; use crate::error::Error; use crate::platform_types::platform::Platform; +use crate::platform_types::platform_state::PlatformState; +use dpp::block::block_info::BlockInfo; use dpp::version::PlatformVersion; use dpp::version::ProtocolVersion; use drive::grovedb::Transaction; @@ -40,6 +42,8 @@ impl Platform { /// pub fn perform_events_on_first_block_of_protocol_change( &self, + platform_state: &PlatformState, + block_info: &BlockInfo, transaction: &Transaction, previous_protocol_version: ProtocolVersion, platform_version: &PlatformVersion, @@ -51,6 +55,8 @@ impl Platform { .perform_events_on_first_block_of_protocol_change { Some(0) => self.perform_events_on_first_block_of_protocol_change_v0( + platform_state, + block_info, transaction, previous_protocol_version, platform_version, diff --git a/packages/rs-drive-abci/src/execution/platform_events/protocol_upgrade/perform_events_on_first_block_of_protocol_change/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/protocol_upgrade/perform_events_on_first_block_of_protocol_change/v0/mod.rs index 62a0d5a46f..f5cf202665 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/protocol_upgrade/perform_events_on_first_block_of_protocol_change/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/protocol_upgrade/perform_events_on_first_block_of_protocol_change/v0/mod.rs @@ -1,7 +1,14 @@ use crate::error::Error; use crate::platform_types::platform::Platform; +use crate::platform_types::platform_state::v0::PlatformStateV0Methods; +use crate::platform_types::platform_state::PlatformState; +use dpp::block::block_info::BlockInfo; +use dpp::dashcore::hashes::Hash; use dpp::version::PlatformVersion; use dpp::version::ProtocolVersion; +use drive::drive::identity::key::fetch::{ + IdentityKeysRequest, KeyIDIdentityPublicKeyPairBTreeMap, KeyRequestType, +}; use drive::drive::identity::withdrawals::paths::{ get_withdrawal_root_path, WITHDRAWAL_TRANSACTIONS_BROADCASTED_KEY, WITHDRAWAL_TRANSACTIONS_SUM_AMOUNT_TREE_KEY, @@ -30,12 +37,19 @@ impl Platform { /// * `Err(Error)`: If there was an issue executing the protocol-specific events. pub(super) fn perform_events_on_first_block_of_protocol_change_v0( &self, + platform_state: &PlatformState, + block_info: &BlockInfo, transaction: &Transaction, previous_protocol_version: ProtocolVersion, platform_version: &PlatformVersion, ) -> Result<(), Error> { if previous_protocol_version < 4 && platform_version.protocol_version >= 4 { - self.transition_to_version_4(transaction, platform_version)?; + self.transition_to_version_4( + platform_state, + block_info, + transaction, + platform_version, + )?; } Ok(()) @@ -57,9 +71,12 @@ impl Platform { /// * `Err(Error)`: If there was an issue creating or updating the necessary data structures. fn transition_to_version_4( &self, + platform_state: &PlatformState, + block_info: &BlockInfo, transaction: &Transaction, platform_version: &PlatformVersion, ) -> Result<(), Error> { + // We are adding the withdrawal transactions sum amount tree let path = get_withdrawal_root_path(); self.drive.grove_insert_if_not_exists( (&path).into(), @@ -69,6 +86,7 @@ impl Platform { None, &platform_version.drive, )?; + // We are adding a tree to store broadcasted transactions that might expire self.drive.grove_insert_if_not_exists( (&path).into(), &WITHDRAWAL_TRANSACTIONS_BROADCASTED_KEY, @@ -77,6 +95,57 @@ impl Platform { None, &platform_version.drive, )?; + // We need to add all masternode owner keys + // This is because owner identities only had a withdrawal key + // But no owner key + for masternode in platform_state.full_masternode_list().values() { + let masternode_id = masternode.pro_tx_hash.to_byte_array(); + let key_request = IdentityKeysRequest { + identity_id: masternode_id, + request_type: KeyRequestType::AllKeys, + limit: None, + offset: None, + }; + + let old_owner_identity_keys = self + .drive + .fetch_identity_keys::( + key_request, + Some(transaction), + platform_version, + )?; + + if old_owner_identity_keys.is_empty() { + continue; + } + + let last_key_id = *old_owner_identity_keys + .keys() + .max() + .expect("there must be keys, we already checked"); + + let new_owner_key = Self::get_owner_identity_owner_key( + masternode.state.owner_address, + last_key_id + 1, + platform_version, + )?; + + tracing::trace!( + identity_id = ?masternode_id, + withdrawal_key = ?new_owner_key, + method = "transition_to_version_4", + "add new owner key to owner identity" + ); + + self.drive.add_new_non_unique_keys_to_identity( + masternode_id, + vec![new_owner_key], + block_info, + true, + Some(transaction), + platform_version, + )?; + } Ok(()) } } diff --git a/packages/rs-drive-abci/src/execution/platform_events/protocol_upgrade/upgrade_protocol_version/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/protocol_upgrade/upgrade_protocol_version/v0/mod.rs index 79b6ce27cd..d8dd13e441 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/protocol_upgrade/upgrade_protocol_version/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/protocol_upgrade/upgrade_protocol_version/v0/mod.rs @@ -99,17 +99,19 @@ impl Platform { // If cached_fee_version is non-empty if let Some((_, last_fee_version)) = previous_fee_versions_map.iter().last() { // Insert the new (epoch_index, fee_version) only if the new fee_version is different from the last_fee_version. - if *last_fee_version != platform_version.fee_version { + if last_fee_version.fee_version_number + != platform_version.fee_version.fee_version_number + { previous_fee_versions_map.insert( epoch_info.current_epoch_index(), - platform_version.fee_version.clone(), + &platform_version.fee_version, ); } // In case of empty cached_fee_version, insert the new (epoch_index, fee_version) } else { previous_fee_versions_map.insert( epoch_info.current_epoch_index(), - platform_version.fee_version.clone(), + &platform_version.fee_version, ); } diff --git a/packages/rs-drive-abci/src/execution/platform_events/withdrawals/rebroadcast_expired_withdrawal_documents/v1/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/withdrawals/rebroadcast_expired_withdrawal_documents/v1/mod.rs index 7e90dc51cb..e2e50b3e5b 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/withdrawals/rebroadcast_expired_withdrawal_documents/v1/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/withdrawals/rebroadcast_expired_withdrawal_documents/v1/mod.rs @@ -71,6 +71,11 @@ where WithdrawalStatus::BROADCASTED as u8, ); + document.set_u64( + withdrawal::properties::TRANSACTION_SIGN_HEIGHT, + block_info.core_height as u64, + ); + document.set_updated_at(Some(block_info.time_ms)); document.increment_revision().map_err(Error::Protocol)?; diff --git a/packages/rs-drive-abci/src/execution/storage/fetch_platform_state/v0/mod.rs b/packages/rs-drive-abci/src/execution/storage/fetch_platform_state/v0/mod.rs index 25960bf5b3..a815e0266a 100644 --- a/packages/rs-drive-abci/src/execution/storage/fetch_platform_state/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/storage/fetch_platform_state/v0/mod.rs @@ -16,8 +16,18 @@ impl Platform { .fetch_platform_state_bytes(transaction, platform_version) .map_err(Error::Drive)? .map(|bytes| { - PlatformState::versioned_deserialize(&bytes, platform_version) - .map_err(Error::Protocol) + let result = PlatformState::versioned_deserialize(&bytes, platform_version) + .map_err(Error::Protocol); + + if result.is_err() { + tracing::error!( + bytes = hex::encode(&bytes), + "Unable deserialize platform state for version {}", + platform_version.protocol_version + ); + } + + result }) .transpose() } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/check_tx_verification/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/check_tx_verification/v0/mod.rs index dde9c1e1f3..acd1515749 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/check_tx_verification/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/check_tx_verification/v0/mod.rs @@ -135,6 +135,8 @@ pub(super) fn state_transition_to_execution_event_for_check_tx_v0<'a, C: CoreRPC // Validating structure let result = state_transition.validate_advanced_structure_from_state( + platform.state.last_block_info(), + platform.config.network, &action, maybe_identity.as_ref(), &mut state_transition_execution_context, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/v0/mod.rs index 46ab19c2fd..f1210e3c0f 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/v0/mod.rs @@ -1,3 +1,4 @@ +use crate::error::execution::ExecutionError; use crate::error::Error; use crate::execution::types::execution_event::ExecutionEvent; use crate::execution::validation::state_transition::transformer::StateTransitionActionTransformerV0; @@ -5,21 +6,20 @@ use crate::platform_types::platform::{PlatformRef, PlatformStateRef}; use crate::platform_types::platform_state::v0::PlatformStateV0Methods; use crate::rpc::core::CoreRPCLike; use dpp::block::block_info::BlockInfo; +use dpp::dashcore::Network; use dpp::fee::Credits; use dpp::identity::PartialIdentity; use dpp::prefunded_specialized_balance::PrefundedSpecializedBalanceIdentifier; use dpp::prelude::ConsensusValidationResult; -use dpp::ProtocolError; -use std::collections::BTreeMap; - -use crate::error::execution::ExecutionError; use dpp::serialization::Signable; use dpp::state_transition::StateTransition; use dpp::validation::SimpleConsensusValidationResult; use dpp::version::{DefaultForPlatformVersion, PlatformVersion}; +use dpp::ProtocolError; use drive::drive::Drive; use drive::grovedb::TransactionArg; use drive::state_transition_action::StateTransitionAction; +use std::collections::BTreeMap; use crate::execution::types::state_transition_execution_context::{StateTransitionExecutionContext}; use crate::execution::validation::state_transition::common::validate_simple_pre_check_balance::ValidateSimplePreCheckBalance; @@ -29,6 +29,7 @@ use crate::execution::validation::state_transition::identity_top_up::StateTransi use crate::execution::validation::state_transition::state_transitions::identity_update::advanced_structure::v0::IdentityUpdateStateTransitionIdentityAndSignaturesValidationV0; use crate::execution::validation::state_transition::state_transitions::identity_top_up::identity_retrieval::v0::IdentityTopUpStateTransitionIdentityRetrievalV0; use crate::execution::validation::state_transition::ValidationMode; +use crate::execution::validation::state_transition::state_transitions::identity_credit_withdrawal::signature_purpose_matches_requirements::IdentityCreditWithdrawalStateTransitionSignaturePurposeMatchesRequirementsValidation; pub(super) fn process_state_transition_v0<'a, C: CoreRPCLike>( platform: &'a PlatformRef, block_info: &BlockInfo, @@ -214,6 +215,8 @@ pub(super) fn process_state_transition_v0<'a, C: CoreRPCLike>( // Validating structure let result = state_transition.validate_advanced_structure_from_state( + block_info, + platform.config.network, &action, maybe_identity.as_ref(), &mut state_transition_execution_context, @@ -402,6 +405,8 @@ pub(crate) trait StateTransitionStructureKnownInStateValidationV0 { /// * `Result` - A result with either a SimpleConsensusValidationResult or an Error. fn validate_advanced_structure_from_state( &self, + block_info: &BlockInfo, + network: Network, action: &StateTransitionAction, maybe_identity: Option<&PartialIdentity>, execution_context: &mut StateTransitionExecutionContext, @@ -745,6 +750,8 @@ impl StateTransitionAdvancedStructureValidationV0 for StateTransition { impl StateTransitionStructureKnownInStateValidationV0 for StateTransition { fn validate_advanced_structure_from_state( &self, + block_info: &BlockInfo, + network: Network, action: &StateTransitionAction, maybe_identity: Option<&PartialIdentity>, execution_context: &mut StateTransitionExecutionContext, @@ -752,6 +759,8 @@ impl StateTransitionStructureKnownInStateValidationV0 for StateTransition { ) -> Result, Error> { match self { StateTransition::DocumentsBatch(st) => st.validate_advanced_structure_from_state( + block_info, + network, action, maybe_identity, execution_context, @@ -773,6 +782,8 @@ impl StateTransitionStructureKnownInStateValidationV0 for StateTransition { ) } StateTransition::MasternodeVote(st) => st.validate_advanced_structure_from_state( + block_info, + network, action, maybe_identity, execution_context, @@ -810,7 +821,6 @@ impl StateTransitionIdentityBasedSignatureValidationV0 for StateTransition { match self { StateTransition::DataContractCreate(_) | StateTransition::DataContractUpdate(_) - | StateTransition::IdentityCreditWithdrawal(_) | StateTransition::IdentityCreditTransfer(_) | StateTransition::DocumentsBatch(_) => { //Basic signature verification @@ -823,6 +833,29 @@ impl StateTransitionIdentityBasedSignatureValidationV0 for StateTransition { platform_version, )?) } + StateTransition::IdentityCreditWithdrawal(credit_withdrawal) => { + let mut consensus_validation_result = self + .validate_state_transition_identity_signed( + drive, + true, + false, + tx, + execution_context, + platform_version, + )?; + + if consensus_validation_result.is_valid_with_data() { + let validation_result = credit_withdrawal + .validate_signature_purpose_matches_requirements( + consensus_validation_result.data.as_ref().unwrap(), + platform_version, + )?; + if !validation_result.is_valid() { + consensus_validation_result.add_errors(validation_result.errors); + } + } + Ok(consensus_validation_result) + } StateTransition::IdentityUpdate(_) => { //Basic signature verification Ok(self.validate_state_transition_identity_signed( diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_create_transition_action/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_create_transition_action/mod.rs index bff6309b3d..7dfa5e8eba 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_create_transition_action/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_create_transition_action/mod.rs @@ -1,3 +1,4 @@ +use dashcore_rpc::dashcore::Network; use dpp::block::block_info::BlockInfo; use dpp::identifier::Identifier; use dpp::validation::SimpleConsensusValidationResult; @@ -20,6 +21,8 @@ pub trait DocumentCreateTransitionActionValidation { fn validate_structure( &self, owner_id: Identifier, + block_info: &BlockInfo, + network: Network, platform_version: &PlatformVersion, ) -> Result; @@ -38,6 +41,8 @@ impl DocumentCreateTransitionActionValidation for DocumentCreateTransitionAction fn validate_structure( &self, owner_id: Identifier, + block_info: &BlockInfo, + network: Network, platform_version: &PlatformVersion, ) -> Result { match platform_version @@ -47,7 +52,7 @@ impl DocumentCreateTransitionActionValidation for DocumentCreateTransitionAction .documents_batch_state_transition .document_create_transition_structure_validation { - 0 => self.validate_structure_v0(owner_id, platform_version), + 0 => self.validate_structure_v0(owner_id, block_info, network, platform_version), version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { method: "DocumentCreateTransitionAction::validate_structure".to_string(), known_versions: vec![0], diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_create_transition_action/structure_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_create_transition_action/structure_v0/mod.rs index 1fbfb2096a..7ae98cf477 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_create_transition_action/structure_v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_create_transition_action/structure_v0/mod.rs @@ -1,6 +1,10 @@ +use dpp::block::block_info::BlockInfo; use dpp::consensus::basic::document::{DocumentCreationNotAllowedError, InvalidDocumentTypeError}; +use dpp::consensus::state::document::document_contest_not_paid_for_error::DocumentContestNotPaidForError; +use dpp::dashcore::Network; use dpp::data_contract::accessors::v0::DataContractV0Getters; use dpp::data_contract::document_type::accessors::DocumentTypeV0Getters; +use dpp::data_contract::document_type::methods::DocumentTypeV0Methods; use dpp::data_contract::document_type::restricted_creation::CreationRestrictionMode; use dpp::data_contract::validate_document::DataContractDocumentValidationMethodsV0; use dpp::identifier::Identifier; @@ -14,6 +18,8 @@ pub(super) trait DocumentCreateTransitionActionStructureValidationV0 { fn validate_structure_v0( &self, owner_id: Identifier, + block_info: &BlockInfo, + network: Network, platform_version: &PlatformVersion, ) -> Result; } @@ -21,6 +27,8 @@ impl DocumentCreateTransitionActionStructureValidationV0 for DocumentCreateTrans fn validate_structure_v0( &self, owner_id: Identifier, + block_info: &BlockInfo, + network: Network, platform_version: &PlatformVersion, ) -> Result { let contract_fetch_info = self.base().data_contract_fetch_info(); @@ -36,6 +44,40 @@ impl DocumentCreateTransitionActionStructureValidationV0 for DocumentCreateTrans )); }; + // Don't do the following validation on testnet before epoch 2080 + // As state transitions already happened that would break this validation + // We want to keep both if-s for better readability + #[allow(clippy::collapsible_if)] + if !(network == Network::Testnet && block_info.epoch.index < 2080) { + // Only for contested documents + if document_type + .contested_vote_poll_for_document_properties(self.data(), platform_version)? + .is_some() + { + let expected_amount = platform_version + .fee_version + .vote_resolution_fund_fees + .contested_document_vote_resolution_fund_required_amount; + if let Some((_, paid_amount)) = self.prefunded_voting_balance() { + if expected_amount != *paid_amount { + return Ok(SimpleConsensusValidationResult::new_with_error( + DocumentContestNotPaidForError::new( + self.base().id(), + expected_amount, + *paid_amount, + ) + .into(), + )); + } + } else { + return Ok(SimpleConsensusValidationResult::new_with_error( + DocumentContestNotPaidForError::new(self.base().id(), expected_amount, 0) + .into(), + )); + } + } + } + match document_type.creation_restriction_mode() { CreationRestrictionMode::NoRestrictions => {} CreationRestrictionMode::OwnerOnly => { diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/advanced_structure/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/advanced_structure/v0/mod.rs index 6c9f7b93b4..5ac5d1630d 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/advanced_structure/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/advanced_structure/v0/mod.rs @@ -1,6 +1,8 @@ use crate::error::Error; +use dpp::block::block_info::BlockInfo; use dpp::consensus::basic::document::InvalidDocumentTransitionIdError; use dpp::consensus::signature::{InvalidSignaturePublicKeySecurityLevelError, SignatureError}; +use dpp::dashcore::Network; use dpp::document::Document; use dpp::identity::identity_public_key::accessors::v0::IdentityPublicKeyGettersV0; use dpp::identity::PartialIdentity; @@ -36,6 +38,8 @@ pub(in crate::execution::validation::state_transition::state_transitions::docume { fn validate_advanced_structure_from_state_v0( &self, + block_info: &BlockInfo, + network: Network, action: &DocumentsBatchTransitionAction, identity: &PartialIdentity, execution_context: &mut StateTransitionExecutionContext, @@ -46,6 +50,8 @@ pub(in crate::execution::validation::state_transition::state_transitions::docume impl DocumentsBatchStateTransitionStructureValidationV0 for DocumentsBatchTransition { fn validate_advanced_structure_from_state_v0( &self, + block_info: &BlockInfo, + network: Network, action: &DocumentsBatchTransitionAction, identity: &PartialIdentity, execution_context: &mut StateTransitionExecutionContext, @@ -119,7 +125,12 @@ impl DocumentsBatchStateTransitionStructureValidationV0 for DocumentsBatchTransi for transition in action.transitions() { match transition { DocumentTransitionAction::CreateAction(create_action) => { - let result = create_action.validate_structure(identity.id, platform_version)?; + let result = create_action.validate_structure( + identity.id, + block_info, + network, + platform_version, + )?; if !result.is_valid() { let bump_action = StateTransitionAction::BumpIdentityDataContractNonceAction( BumpIdentityDataContractNonceAction::from_borrowed_document_base_transition_action(transition.base().expect("there is always a base for the create action"), self.owner_id(), self.user_fee_increase()), diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/mod.rs index eaa0f93bcc..1cb7c26a62 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/mod.rs @@ -8,6 +8,7 @@ mod state; mod transformer; use dpp::block::block_info::BlockInfo; +use dpp::dashcore::Network; use dpp::identity::PartialIdentity; use dpp::prelude::*; use dpp::state_transition::documents_batch_transition::DocumentsBatchTransition; @@ -137,6 +138,8 @@ impl StateTransitionNonceValidationV0 for DocumentsBatchTransition { impl StateTransitionStructureKnownInStateValidationV0 for DocumentsBatchTransition { fn validate_advanced_structure_from_state( &self, + block_info: &BlockInfo, + network: Network, action: &StateTransitionAction, identity: Option<&PartialIdentity>, execution_context: &mut StateTransitionExecutionContext, @@ -162,6 +165,8 @@ impl StateTransitionStructureKnownInStateValidationV0 for DocumentsBatchTransiti ))); }; self.validate_advanced_structure_from_state_v0( + block_info, + network, documents_batch_transition_action, identity, execution_context, @@ -299,6 +304,14 @@ mod tests { use crate::platform_types::state_transitions_processing_result::StateTransitionExecutionResult::PaidConsensusError; use crate::test::helpers::fast_forward_to_block::fast_forward_to_block; use dpp::consensus::state::state_error::StateError; + use dpp::dashcore::Network; + use dpp::dashcore::Network::Testnet; + use dpp::identity::SecurityLevel; + use dpp::state_transition::documents_batch_transition::document_base_transition::DocumentBaseTransition; + use dpp::state_transition::documents_batch_transition::document_create_transition::DocumentCreateTransitionV0; + use dpp::state_transition::documents_batch_transition::{DocumentCreateTransition, DocumentsBatchTransitionV0}; + use dpp::state_transition::StateTransition; + use crate::config::PlatformConfig; #[test] fn test_document_creation() { @@ -1111,6 +1124,557 @@ mod tests { assert_eq!(second_contender.vote_tally(), Some(0)); } + #[test] + fn test_document_creation_on_contested_unique_index_should_fail_if_not_paying_for_it() { + let platform_version = PlatformVersion::latest(); + let platform_config = PlatformConfig { + network: Network::Dash, + ..Default::default() + }; + let mut platform = TestPlatformBuilder::new() + .with_latest_protocol_version() + .with_config(platform_config) + .build_with_mock_rpc() + .set_genesis_state(); + + let mut rng = StdRng::seed_from_u64(433); + + let platform_state = platform.state.load(); + + let (identity_1, signer_1, key_1) = + setup_identity(&mut platform, 958, dash_to_credits!(0.5)); + + let dpns = platform.drive.cache.system_data_contracts.load_dpns(); + let dpns_contract = dpns.clone(); + + let preorder = dpns_contract + .document_type_for_name("preorder") + .expect("expected a profile document type"); + + assert!(!preorder.documents_mutable()); + assert!(preorder.documents_can_be_deleted()); + assert!(!preorder.documents_transferable().is_transferable()); + + let domain = dpns_contract + .document_type_for_name("domain") + .expect("expected a profile document type"); + + assert!(!domain.documents_mutable()); + // Deletion is disabled with data trigger + assert!(domain.documents_can_be_deleted()); + assert!(domain.documents_transferable().is_transferable()); + + let entropy = Bytes32::random_with_rng(&mut rng); + + let mut preorder_document_1 = preorder + .random_document_with_identifier_and_entropy( + &mut rng, + identity_1.id(), + entropy, + DocumentFieldFillType::FillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + let mut document_1 = domain + .random_document_with_identifier_and_entropy( + &mut rng, + identity_1.id(), + entropy, + DocumentFieldFillType::FillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + document_1.set("parentDomainName", "dash".into()); + document_1.set("normalizedParentDomainName", "dash".into()); + document_1.set("label", "quantum".into()); + document_1.set("normalizedLabel", "quantum".into()); + document_1.set("records.identity", document_1.owner_id().into()); + document_1.set("subdomainRules.allowSubdomains", false.into()); + + let salt_1: [u8; 32] = rng.gen(); + + let mut salted_domain_buffer_1: Vec = vec![]; + salted_domain_buffer_1.extend(salt_1); + salted_domain_buffer_1.extend("quantum.dash".as_bytes()); + + let salted_domain_hash_1 = hash_double(salted_domain_buffer_1); + + preorder_document_1.set("saltedDomainHash", salted_domain_hash_1.into()); + + document_1.set("preorderSalt", salt_1.into()); + + let documents_batch_create_preorder_transition_1 = + DocumentsBatchTransition::new_document_creation_transition_from_document( + preorder_document_1, + preorder, + entropy.0, + &key_1, + 2, + 0, + &signer_1, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_preorder_transition_1 = + documents_batch_create_preorder_transition_1 + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); + + let owner_id = document_1.owner_id(); + let create_transition: DocumentCreateTransition = DocumentCreateTransitionV0 { + base: DocumentBaseTransition::from_document( + &document_1, + domain, + 3, + platform_version, + None, + ) + .expect("expected a base transition"), + entropy: entropy.0, + data: document_1.clone().properties_consumed(), + // Sending 0 balance that should not be valid + prefunded_voting_balance: None, + } + .into(); + let documents_batch_inner_create_transition_1: DocumentsBatchTransition = + DocumentsBatchTransitionV0 { + owner_id, + transitions: vec![create_transition.into()], + user_fee_increase: 0, + signature_public_key_id: 0, + signature: Default::default(), + } + .into(); + let mut documents_batch_create_transition_1: StateTransition = + documents_batch_inner_create_transition_1.into(); + documents_batch_create_transition_1 + .sign_external(&key_1, &signer_1, Some(|_, _| Ok(SecurityLevel::HIGH))) + .expect("expected to sign"); + + let documents_batch_create_serialized_transition_1 = + documents_batch_create_transition_1 + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![documents_batch_create_serialized_preorder_transition_1.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + assert_eq!(processing_result.valid_count(), 1); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![documents_batch_create_serialized_transition_1.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + assert_matches!( + processing_result.execution_results().as_slice(), + [PaidConsensusError( + ConsensusError::StateError(StateError::DocumentContestNotPaidForError(_)), + _ + )] + ); + + // Now let's run a query for the vote totals + + let config = bincode::config::standard() + .with_big_endian() + .with_no_limit(); + + let dash_encoded = bincode::encode_to_vec(Value::Text("dash".to_string()), config) + .expect("expected to encode the word dash"); + + let quantum_encoded = + bincode::encode_to_vec(Value::Text("quantum".to_string()), config) + .expect("expected to encode the word quantum"); + + let index_name = "parentNameAndLabel".to_string(); + + let query_validation_result = platform + .query_contested_resource_vote_state( + GetContestedResourceVoteStateRequest { + version: Some(get_contested_resource_vote_state_request::Version::V0( + GetContestedResourceVoteStateRequestV0 { + contract_id: dpns_contract.id().to_vec(), + document_type_name: domain.name().clone(), + index_name: index_name.clone(), + index_values: vec![dash_encoded.clone(), quantum_encoded.clone()], + result_type: ResultType::DocumentsAndVoteTally as i32, + allow_include_locked_and_abstaining_vote_tally: false, + start_at_identifier_info: None, + count: None, + prove: false, + }, + )), + }, + &platform_state, + platform_version, + ) + .expect("expected to execute query") + .into_data() + .expect("expected query to be valid"); + + let get_contested_resource_vote_state_response::Version::V0( + GetContestedResourceVoteStateResponseV0 { + metadata: _, + result, + }, + ) = query_validation_result.version.expect("expected a version"); + + let Some( + get_contested_resource_vote_state_response_v0::Result::ContestedResourceContenders( + get_contested_resource_vote_state_response_v0::ContestedResourceContenders { + contenders, + abstain_vote_tally, + lock_vote_tally, + finished_vote_info, + }, + ), + ) = result + else { + panic!("expected contenders") + }; + + assert_eq!(abstain_vote_tally, None); + + assert_eq!(lock_vote_tally, None); + + assert_eq!(finished_vote_info, None); + + assert_eq!(contenders.len(), 0); + + let drive_query = DriveDocumentQuery::new_primary_key_single_item_query( + &dpns, + domain, + document_1.id(), + ); + + let documents = platform + .drive + .query_documents(drive_query, None, false, None, None) + .expect("expected to get back documents") + .documents_owned(); + + assert!(documents.first().is_none()); + } + + #[test] + fn test_document_creation_on_contested_unique_index_should_not_fail_if_not_paying_for_it_on_testnet_before_epoch_2080( + ) { + let platform_version = PlatformVersion::latest(); + let platform_config = PlatformConfig { + network: Testnet, + ..Default::default() + }; + let mut platform = TestPlatformBuilder::new() + .with_latest_protocol_version() + .with_config(platform_config) + .build_with_mock_rpc() + .set_genesis_state(); + + let mut rng = StdRng::seed_from_u64(433); + + let platform_state = platform.state.load(); + + let (identity_1, signer_1, key_1) = + setup_identity(&mut platform, 958, dash_to_credits!(0.5)); + + let dpns = platform.drive.cache.system_data_contracts.load_dpns(); + let dpns_contract = dpns.clone(); + + let preorder = dpns_contract + .document_type_for_name("preorder") + .expect("expected a profile document type"); + + assert!(!preorder.documents_mutable()); + assert!(preorder.documents_can_be_deleted()); + assert!(!preorder.documents_transferable().is_transferable()); + + let domain = dpns_contract + .document_type_for_name("domain") + .expect("expected a profile document type"); + + assert!(!domain.documents_mutable()); + // Deletion is disabled with data trigger + assert!(domain.documents_can_be_deleted()); + assert!(domain.documents_transferable().is_transferable()); + + let entropy = Bytes32::random_with_rng(&mut rng); + + let mut preorder_document_1 = preorder + .random_document_with_identifier_and_entropy( + &mut rng, + identity_1.id(), + entropy, + DocumentFieldFillType::FillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + let mut document_1 = domain + .random_document_with_identifier_and_entropy( + &mut rng, + identity_1.id(), + entropy, + DocumentFieldFillType::FillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + document_1.set("parentDomainName", "dash".into()); + document_1.set("normalizedParentDomainName", "dash".into()); + document_1.set("label", "quantum".into()); + document_1.set("normalizedLabel", "quantum".into()); + document_1.set("records.identity", document_1.owner_id().into()); + document_1.set("subdomainRules.allowSubdomains", false.into()); + + let salt_1: [u8; 32] = rng.gen(); + + let mut salted_domain_buffer_1: Vec = vec![]; + salted_domain_buffer_1.extend(salt_1); + salted_domain_buffer_1.extend("quantum.dash".as_bytes()); + + let salted_domain_hash_1 = hash_double(salted_domain_buffer_1); + + preorder_document_1.set("saltedDomainHash", salted_domain_hash_1.into()); + + document_1.set("preorderSalt", salt_1.into()); + + let documents_batch_create_preorder_transition_1 = + DocumentsBatchTransition::new_document_creation_transition_from_document( + preorder_document_1, + preorder, + entropy.0, + &key_1, + 2, + 0, + &signer_1, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_preorder_transition_1 = + documents_batch_create_preorder_transition_1 + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); + + let owner_id = document_1.owner_id(); + let create_transition: DocumentCreateTransition = DocumentCreateTransitionV0 { + base: DocumentBaseTransition::from_document( + &document_1, + domain, + 3, + platform_version, + None, + ) + .expect("expected a base transition"), + entropy: entropy.0, + data: document_1.clone().properties_consumed(), + prefunded_voting_balance: None, + } + .into(); + let documents_batch_inner_create_transition_1: DocumentsBatchTransition = + DocumentsBatchTransitionV0 { + owner_id, + transitions: vec![create_transition.into()], + user_fee_increase: 0, + signature_public_key_id: 0, + signature: Default::default(), + } + .into(); + let mut documents_batch_create_transition_1: StateTransition = + documents_batch_inner_create_transition_1.into(); + documents_batch_create_transition_1 + .sign_external(&key_1, &signer_1, Some(|_, _| Ok(SecurityLevel::HIGH))) + .expect("expected to sign"); + + let documents_batch_create_serialized_transition_1 = + documents_batch_create_transition_1 + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![documents_batch_create_serialized_preorder_transition_1.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + assert_eq!(processing_result.valid_count(), 1); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![documents_batch_create_serialized_transition_1.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::SuccessfulExecution(..)] + ); + + // Now let's run a query for the vote totals + + let config = bincode::config::standard() + .with_big_endian() + .with_no_limit(); + + let dash_encoded = bincode::encode_to_vec(Value::Text("dash".to_string()), config) + .expect("expected to encode the word dash"); + + let quantum_encoded = + bincode::encode_to_vec(Value::Text("quantum".to_string()), config) + .expect("expected to encode the word quantum"); + + let index_name = "parentNameAndLabel".to_string(); + + let query_validation_result = platform + .query_contested_resource_vote_state( + GetContestedResourceVoteStateRequest { + version: Some(get_contested_resource_vote_state_request::Version::V0( + GetContestedResourceVoteStateRequestV0 { + contract_id: dpns_contract.id().to_vec(), + document_type_name: domain.name().clone(), + index_name: index_name.clone(), + index_values: vec![dash_encoded.clone(), quantum_encoded.clone()], + result_type: ResultType::DocumentsAndVoteTally as i32, + allow_include_locked_and_abstaining_vote_tally: false, + start_at_identifier_info: None, + count: None, + prove: false, + }, + )), + }, + &platform_state, + platform_version, + ) + .expect("expected to execute query") + .into_data() + .expect("expected query to be valid"); + + let get_contested_resource_vote_state_response::Version::V0( + GetContestedResourceVoteStateResponseV0 { + metadata: _, + result, + }, + ) = query_validation_result.version.expect("expected a version"); + + let Some( + get_contested_resource_vote_state_response_v0::Result::ContestedResourceContenders( + get_contested_resource_vote_state_response_v0::ContestedResourceContenders { + contenders, + abstain_vote_tally, + lock_vote_tally, + finished_vote_info, + }, + ), + ) = result + else { + panic!("expected contenders") + }; + + assert_eq!(abstain_vote_tally, None); + + assert_eq!(lock_vote_tally, None); + + assert_eq!(finished_vote_info, None); + + assert_eq!(contenders.len(), 0); // no contenders should have been created the document should just exist + + let drive_query = DriveDocumentQuery::new_primary_key_single_item_query( + &dpns, + domain, + document_1.id(), + ); + + let documents = platform + .drive + .query_documents(drive_query, None, false, None, None) + .expect("expected to get back documents") + .documents_owned(); + + assert!(documents.first().is_some()); + } + #[test] fn test_document_creation_on_contested_unique_index_should_fail_if_reusing_entropy() { let platform_version = PlatformVersion::latest(); diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/identity_credit_withdrawal/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/identity_credit_withdrawal/mod.rs index c2eaee7f71..3b42e8e744 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/identity_credit_withdrawal/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/identity_credit_withdrawal/mod.rs @@ -1,5 +1,6 @@ mod balance; mod nonce; +pub(crate) mod signature_purpose_matches_requirements; mod state; mod structure; @@ -131,7 +132,9 @@ impl StateTransitionStateValidationV0 for IdentityCreditWithdrawalTransition { #[cfg(test)] mod tests { use crate::config::{PlatformConfig, PlatformTestConfig}; - use crate::execution::validation::state_transition::tests::setup_identity_with_withdrawal_key_and_system_credits; + use crate::execution::validation::state_transition::tests::{ + setup_identity_with_withdrawal_key_and_system_credits, setup_masternode_owner_identity, + }; use crate::platform_types::state_transitions_processing_result::StateTransitionExecutionResult; use crate::test::helpers::fast_forward_to_block::fast_forward_to_block; use crate::test::helpers::setup::TestPlatformBuilder; @@ -378,6 +381,154 @@ mod tests { ); } + #[test] + fn test_masternode_credit_withdrawal_without_withdrawal_address_creates_withdrawal_document_when_signing_with_withdrawal_key( + ) { + let platform_version = PlatformVersion::latest(); + let platform_config = PlatformConfig { + testing_configs: PlatformTestConfig { + disable_instant_lock_signature_verification: true, + ..Default::default() + }, + ..Default::default() + }; + + let mut rng = StdRng::seed_from_u64(529); + + let mut platform = TestPlatformBuilder::new() + .with_config(platform_config) + .with_latest_protocol_version() + .build_with_mock_rpc() + .set_genesis_state(); + + fast_forward_to_block(&platform, 1_200_000_000, 900, 42, 1, false); //next epoch + + let (identity, signer, _, _) = setup_masternode_owner_identity( + &mut platform, + rng.gen(), + dash_to_credits!(0.5), + platform_version, + ); + + let platform_state = platform.state.load(); + + let withdrawal_amount = dash_to_credits!(0.1); + + let credit_withdrawal_transition = IdentityCreditWithdrawalTransition::try_from_identity( + &identity, + None, + withdrawal_amount, + Pooling::Never, + 1, + 0, + signer, + None, + PreferredKeyPurposeForSigningWithdrawal::TransferOnly, + 2, + platform_version, + None, + ) + .expect("expected a credit withdrawal transition"); + + let credit_withdrawal_transition_serialized_transition = credit_withdrawal_transition + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![credit_withdrawal_transition_serialized_transition.clone()], + &platform_state, + &BlockInfo::default_with_time(1_200_001_000), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::SuccessfulExecution(..)] + ); + } + + #[test] + fn test_masternode_credit_withdrawal_without_withdrawal_address_creates_withdrawal_document_when_signing_with_owner_key( + ) { + let platform_version = PlatformVersion::latest(); + let platform_config = PlatformConfig { + testing_configs: PlatformTestConfig { + disable_instant_lock_signature_verification: true, + ..Default::default() + }, + ..Default::default() + }; + + let mut rng = StdRng::seed_from_u64(529); + + let mut platform = TestPlatformBuilder::new() + .with_config(platform_config) + .with_latest_protocol_version() + .build_with_mock_rpc() + .set_genesis_state(); + + fast_forward_to_block(&platform, 1_200_000_000, 900, 42, 1, false); //next epoch + + let (identity, signer, _, _) = setup_masternode_owner_identity( + &mut platform, + rng.gen(), + dash_to_credits!(0.5), + platform_version, + ); + + let platform_state = platform.state.load(); + + let withdrawal_amount = dash_to_credits!(0.1); + + let credit_withdrawal_transition = IdentityCreditWithdrawalTransition::try_from_identity( + &identity, + None, + withdrawal_amount, + Pooling::Never, + 1, + 0, + signer, + None, + PreferredKeyPurposeForSigningWithdrawal::OwnerOnly, + 2, + platform_version, + None, + ) + .expect("expected a credit withdrawal transition"); + + let credit_withdrawal_transition_serialized_transition = credit_withdrawal_transition + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![credit_withdrawal_transition_serialized_transition.clone()], + &platform_state, + &BlockInfo::default_with_time(1_200_001_000), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::SuccessfulExecution(..)] + ); + } + mod errors { use super::*; use dpp::consensus::state::state_error::StateError; @@ -458,5 +609,84 @@ mod tests { )] ); } + + #[test] + fn test_masternode_credit_withdrawal_with_withdrawal_address_creates_when_signing_with_owner_key_should_fail( + ) { + let platform_version = PlatformVersion::latest(); + let platform_config = PlatformConfig { + testing_configs: PlatformTestConfig { + disable_instant_lock_signature_verification: true, + ..Default::default() + }, + ..Default::default() + }; + + let mut rng = StdRng::seed_from_u64(529); + + let mut platform = TestPlatformBuilder::new() + .with_config(platform_config) + .with_latest_protocol_version() + .build_with_mock_rpc() + .set_genesis_state(); + + fast_forward_to_block(&platform, 1_200_000_000, 900, 42, 1, false); //next epoch + + let (identity, signer, _, _) = setup_masternode_owner_identity( + &mut platform, + rng.gen(), + dash_to_credits!(0.5), + platform_version, + ); + + let platform_state = platform.state.load(); + + let withdrawal_amount = dash_to_credits!(0.1); + + let credit_withdrawal_transition = + IdentityCreditWithdrawalTransition::try_from_identity( + &identity, + Some(CoreScript::random_p2pkh(&mut rng)), + withdrawal_amount, + Pooling::Never, + 1, + 0, + signer, + None, + PreferredKeyPurposeForSigningWithdrawal::OwnerOnly, + 2, + platform_version, + None, + ) + .expect("expected a credit withdrawal transition"); + + let credit_withdrawal_transition_serialized_transition = credit_withdrawal_transition + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![credit_withdrawal_transition_serialized_transition.clone()], + &platform_state, + &BlockInfo::default_with_time(1_200_001_000), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::BasicError( + BasicError::WithdrawalOutputScriptNotAllowedWhenSigningWithOwnerKeyError(_) + ) + )] + ); + } } } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/identity_credit_withdrawal/signature_purpose_matches_requirements/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/identity_credit_withdrawal/signature_purpose_matches_requirements/mod.rs new file mode 100644 index 0000000000..d82846f84e --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/identity_credit_withdrawal/signature_purpose_matches_requirements/mod.rs @@ -0,0 +1,45 @@ +pub(crate) mod v0; + +use crate::error::Error; +use dpp::identity::PartialIdentity; +use dpp::state_transition::identity_credit_withdrawal_transition::IdentityCreditWithdrawalTransition; +use dpp::validation::SimpleConsensusValidationResult; +use dpp::version::PlatformVersion; +use crate::error::execution::ExecutionError; +use crate::execution::validation::state_transition::identity_credit_withdrawal::signature_purpose_matches_requirements::v0::IdentityCreditWithdrawalStateTransitionSignaturePurposeMatchesRequirementsValidationV0; + +pub(in crate::execution::validation::state_transition) trait IdentityCreditWithdrawalStateTransitionSignaturePurposeMatchesRequirementsValidation +{ + fn validate_signature_purpose_matches_requirements( + &self, + identity: &PartialIdentity, + platform_version: &PlatformVersion, + ) -> Result; +} + +impl IdentityCreditWithdrawalStateTransitionSignaturePurposeMatchesRequirementsValidation + for IdentityCreditWithdrawalTransition +{ + fn validate_signature_purpose_matches_requirements( + &self, + identity: &PartialIdentity, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .drive_abci + .validation_and_processing + .state_transitions + .identity_credit_withdrawal_state_transition_purpose_matches_requirements + { + 0 => self.validate_signature_purpose_matches_requirements_v0( + identity, + platform_version, + ), + version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { + method: "identity credit withdrawal transition: validate_signature_purpose_matches_requirements".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/identity_credit_withdrawal/signature_purpose_matches_requirements/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/identity_credit_withdrawal/signature_purpose_matches_requirements/v0/mod.rs new file mode 100644 index 0000000000..4bdd1ff1a2 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/identity_credit_withdrawal/signature_purpose_matches_requirements/v0/mod.rs @@ -0,0 +1,53 @@ +use crate::error::execution::ExecutionError; +use crate::error::Error; +use dpp::consensus::basic::identity::WithdrawalOutputScriptNotAllowedWhenSigningWithOwnerKeyError; +use dpp::identity::identity_public_key::accessors::v0::IdentityPublicKeyGettersV0; +use dpp::identity::{PartialIdentity, Purpose}; +use dpp::state_transition::identity_credit_withdrawal_transition::accessors::IdentityCreditWithdrawalTransitionAccessorsV0; +use dpp::state_transition::identity_credit_withdrawal_transition::IdentityCreditWithdrawalTransition; +use dpp::state_transition::StateTransitionIdentitySigned; +use dpp::validation::SimpleConsensusValidationResult; +use dpp::version::PlatformVersion; + +pub(super) trait IdentityCreditWithdrawalStateTransitionSignaturePurposeMatchesRequirementsValidationV0 +{ + fn validate_signature_purpose_matches_requirements_v0( + &self, + identity: &PartialIdentity, + platform_version: &PlatformVersion, + ) -> Result; +} + +impl IdentityCreditWithdrawalStateTransitionSignaturePurposeMatchesRequirementsValidationV0 + for IdentityCreditWithdrawalTransition +{ + fn validate_signature_purpose_matches_requirements_v0( + &self, + identity: &PartialIdentity, + _platform_version: &PlatformVersion, + ) -> Result { + let mut result = SimpleConsensusValidationResult::default(); + + if let Some(output_script) = self.output_script() { + let Some(signing_key) = identity + .loaded_public_keys + .get(&self.signature_public_key_id()) + else { + return Err(Error::Execution(ExecutionError::CorruptedCodeExecution( + "we should have a loaded key at this point", + ))); + }; + + if signing_key.purpose() == Purpose::OWNER { + result.add_error( + WithdrawalOutputScriptNotAllowedWhenSigningWithOwnerKeyError::new( + output_script.clone(), + signing_key.id(), + ), + ); + } + } + + Ok(result) + } +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/identity_update/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/identity_update/mod.rs index 0b6adcdf0d..629240407a 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/identity_update/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/identity_update/mod.rs @@ -116,9 +116,13 @@ mod tests { use crate::execution::validation::state_transition::tests::{ setup_add_key_to_identity, setup_identity_return_master_key, }; + use crate::platform_types::state_transitions_processing_result::StateTransitionExecutionResult; use crate::test::helpers::setup::TestPlatformBuilder; + use assert_matches::assert_matches; use dpp::block::block_info::BlockInfo; + use dpp::consensus::ConsensusError; use dpp::dash_to_credits; + use dpp::dashcore::key::{KeyPair, Secp256k1}; use dpp::data_contract::accessors::v0::DataContractV0Getters; use dpp::identity::accessors::IdentityGettersV0; use dpp::identity::contract_bounds::ContractBounds; @@ -128,8 +132,11 @@ mod tests { use dpp::serialization::{PlatformSerializable, Signable}; use dpp::state_transition::identity_update_transition::v0::IdentityUpdateTransitionV0; use dpp::state_transition::identity_update_transition::IdentityUpdateTransition; + use dpp::state_transition::public_key_in_creation::v0::IdentityPublicKeyInCreationV0; use dpp::state_transition::StateTransition; use platform_version::version::PlatformVersion; + use rand::rngs::StdRng; + use rand::SeedableRng; #[test] fn test_identity_update_that_disables_an_authentication_key() { @@ -337,4 +344,109 @@ mod tests { .join(" | ") ); } + + #[test] + fn test_identity_update_adding_owner_key_not_allowed() { + let platform_config = PlatformConfig { + testing_configs: PlatformTestConfig { + disable_instant_lock_signature_verification: true, + ..Default::default() + }, + ..Default::default() + }; + + let platform_version = PlatformVersion::latest(); + + let mut platform = TestPlatformBuilder::new() + .with_config(platform_config) + .build_with_mock_rpc() + .set_genesis_state(); + + let (identity, signer, key) = + setup_identity_return_master_key(&mut platform, 958, dash_to_credits!(0.1)); + + let platform_state = platform.state.load(); + + let secp = Secp256k1::new(); + + let mut rng = StdRng::seed_from_u64(1292); + + let new_key_pair = KeyPair::new(&secp, &mut rng); + + let new_key = IdentityPublicKeyInCreationV0 { + id: 2, + purpose: Purpose::OWNER, + security_level: SecurityLevel::HIGH, + key_type: KeyType::ECDSA_SECP256K1, + read_only: false, + data: new_key_pair.public_key().serialize().to_vec().into(), + signature: Default::default(), + contract_bounds: None, + }; + + let update_transition: IdentityUpdateTransition = IdentityUpdateTransitionV0 { + identity_id: identity.id(), + revision: 1, + nonce: 1, + add_public_keys: vec![new_key.into()], + disable_public_keys: vec![], + user_fee_increase: 0, + signature_public_key_id: key.id(), + signature: Default::default(), + } + .into(); + + let mut update_transition: StateTransition = update_transition.into(); + + let data = update_transition + .signable_bytes() + .expect("expected signable bytes"); + update_transition.set_signature( + signer + .sign(&key, data.as_slice()) + .expect("expected to sign"), + ); + + let update_transition_bytes = update_transition + .serialize_to_bytes() + .expect("expected to serialize"); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![update_transition_bytes.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + true, + None, + ) + .expect("expected to process state transition"); + + // We expect there to be an error because you should not be able to add owner keys + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::BasicError(_) + )] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit"); + + let issues = platform + .drive + .grove + .visualize_verify_grovedb(None, true, false, &platform_version.drive.grove_version) + .expect("expected to have no issues"); + + assert_eq!(issues.len(), 0); + } } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/masternode_vote/advanced_structure/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/masternode_vote/advanced_structure/mod.rs index b44732c3d0..40cc8ef3c5 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/masternode_vote/advanced_structure/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/masternode_vote/advanced_structure/mod.rs @@ -3,6 +3,8 @@ use crate::error::Error; use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; use crate::execution::validation::state_transition::masternode_vote::advanced_structure::v0::MasternodeVoteStateTransitionAdvancedStructureValidationV0; use crate::execution::validation::state_transition::processor::v0::StateTransitionStructureKnownInStateValidationV0; +use dpp::block::block_info::BlockInfo; +use dpp::dashcore::Network; use dpp::identity::PartialIdentity; use dpp::prelude::ConsensusValidationResult; use dpp::state_transition::masternode_vote_transition::MasternodeVoteTransition; @@ -14,6 +16,8 @@ pub(crate) mod v0; impl StateTransitionStructureKnownInStateValidationV0 for MasternodeVoteTransition { fn validate_advanced_structure_from_state( &self, + _block_info: &BlockInfo, + _network: Network, action: &StateTransitionAction, identity: Option<&PartialIdentity>, execution_context: &mut StateTransitionExecutionContext, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/mod.rs index 51df74cde5..b0986e026d 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/mod.rs @@ -512,6 +512,111 @@ pub(in crate::execution) mod tests { ); } + pub(in crate::execution) fn setup_masternode_owner_identity( + platform: &mut TempPlatform, + seed: u64, + credits: Credits, + platform_version: &PlatformVersion, + ) -> (Identity, SimpleSigner, IdentityPublicKey, IdentityPublicKey) { + let mut signer = SimpleSigner::default(); + + platform + .drive + .add_to_system_credits(credits, None, platform_version) + .expect("expected to add to system credits"); + + let mut rng = StdRng::seed_from_u64(seed); + + let (transfer_key, transfer_private_key) = + IdentityPublicKey::random_masternode_transfer_key_with_rng( + 0, + &mut rng, + platform_version, + ) + .expect("expected to get key pair"); + + let (owner_key, owner_private_key) = + IdentityPublicKey::random_masternode_owner_key_with_rng(1, &mut rng, platform_version) + .expect("expected to get key pair"); + + let owner_address = owner_key + .public_key_hash() + .expect("expected a public key hash"); + + let payout_address = transfer_key + .public_key_hash() + .expect("expected a public key hash"); + + signer.add_key(transfer_key.clone(), transfer_private_key.clone()); + signer.add_key(owner_key.clone(), owner_private_key.clone()); + + let pro_tx_hash_bytes: [u8; 32] = rng.gen(); + + let identity: Identity = IdentityV0 { + id: pro_tx_hash_bytes.into(), + public_keys: BTreeMap::from([(0, transfer_key.clone()), (1, owner_key.clone())]), + balance: credits, + revision: 0, + } + .into(); + + // We just add this identity to the system first + + platform + .drive + .add_new_identity( + identity.clone(), + true, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add a new identity"); + + let mut platform_state = platform.state.load().clone().deref().clone(); + + let pro_tx_hash = ProTxHash::from_byte_array(pro_tx_hash_bytes); + + let random_ip = Ipv4Addr::new( + rng.gen_range(0..255), + rng.gen_range(0..255), + rng.gen_range(0..255), + rng.gen_range(0..255), + ); + + platform_state.full_masternode_list_mut().insert( + pro_tx_hash, + MasternodeListItem { + node_type: MasternodeType::Regular, + pro_tx_hash, + collateral_hash: Txid::from_byte_array(rng.gen()), + collateral_index: 0, + collateral_address: rng.gen(), + operator_reward: 0.0, + state: DMNState { + service: SocketAddr::new(IpAddr::V4(random_ip), 19999), + registered_height: 0, + pose_revived_height: None, + pose_ban_height: None, + revocation_reason: 0, + owner_address, + voting_address: rng.gen(), + payout_address, + pub_key_operator: vec![], + operator_payout_address: None, + platform_node_id: None, + platform_p2p_port: None, + platform_http_port: None, + }, + }, + ); + + platform.state.store(Arc::new(platform_state)); + + (identity, signer, owner_key, transfer_key) + } + pub(in crate::execution) fn setup_masternode_voting_identity( platform: &mut TempPlatform, seed: u64, diff --git a/packages/rs-drive-abci/src/logging/logger.rs b/packages/rs-drive-abci/src/logging/logger.rs index 121ce76b93..6646a783c8 100644 --- a/packages/rs-drive-abci/src/logging/logger.rs +++ b/packages/rs-drive-abci/src/logging/logger.rs @@ -5,7 +5,7 @@ use crate::logging::{LogConfigs, LogFormat, LogLevel}; use lazy_static::__Deref; use std::collections::HashMap; use std::fmt::Debug; -use std::io::Write; +use std::io::{IsTerminal, Write}; use std::sync::Arc; use std::sync::Mutex; use tracing_subscriber::fmt; @@ -305,9 +305,9 @@ impl Logger { fn layer(&self) -> Result, Error> { let ansi = self .color - .unwrap_or(match self.destination.lock().unwrap().deref() { - LogDestinationWriter::StdOut => atty::is(atty::Stream::Stdout), - LogDestinationWriter::StdErr => atty::is(atty::Stream::Stderr), + .unwrap_or_else(|| match self.destination.lock().unwrap().deref() { + LogDestinationWriter::StdOut => std::io::stdout().is_terminal(), + LogDestinationWriter::StdErr => std::io::stderr().is_terminal(), _ => false, }); diff --git a/packages/rs-drive-abci/src/platform_types/platform_state/mod.rs b/packages/rs-drive-abci/src/platform_types/platform_state/mod.rs index e937924c94..d2236ef84c 100644 --- a/packages/rs-drive-abci/src/platform_types/platform_state/mod.rs +++ b/packages/rs-drive-abci/src/platform_types/platform_state/mod.rs @@ -4,8 +4,8 @@ pub mod v0; use crate::error::Error; use crate::platform_types::platform_state::v0::{ - MasternodeListChanges, PlatformStateForSavingV0, PlatformStateV0, PlatformStateV0Methods, - PlatformStateV0PrivateMethods, + MasternodeListChanges, PlatformStateForSavingV0, PlatformStateForSavingV1, PlatformStateV0, + PlatformStateV0Methods, PlatformStateV0PrivateMethods, }; use crate::platform_types::validator_set::ValidatorSet; @@ -42,23 +42,8 @@ pub enum PlatformState { pub enum PlatformStateForSaving { /// Version 0 V0(PlatformStateForSavingV0), -} - -impl PlatformStateForSaving { - /// Retrieves the current protocol version used in consensus. - /// - /// Matches against `PlatformStateForSaving` variants to extract the protocol version. - /// - /// # Returns - /// A `ProtocolVersion` indicating the current consensus protocol version. - #[allow(dead_code)] - #[deprecated(note = "This function is marked as unused.")] - #[allow(deprecated)] - pub fn current_protocol_version_in_consensus(&self) -> ProtocolVersion { - match self { - PlatformStateForSaving::V0(v0) => v0.current_protocol_version_in_consensus, - } - } + /// Version 1 + V1(PlatformStateForSavingV1), } impl PlatformSerializable for PlatformState { @@ -153,11 +138,11 @@ impl TryFromPlatformVersioned for PlatformStateForSaving { match platform_version .drive_abci .structs - .platform_state_for_saving_structure + .platform_state_for_saving_structure_default { 0 => { - let saving_v0: PlatformStateForSavingV0 = v0.try_into()?; - Ok(saving_v0.into()) + let saving_v1: PlatformStateForSavingV1 = v0.try_into()?; + Ok(saving_v1.into()) } version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { method: @@ -189,7 +174,23 @@ impl TryFromPlatformVersioned for PlatformState { } version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { method: - "PlatformState::try_from_platform_versioned(PlatformStateForSaving)" + "PlatformState::try_from_platform_versioned(PlatformStateForSavingV0)" + .to_string(), + known_versions: vec![0], + received: version, + })), + } + } + PlatformStateForSaving::V1(v1) => { + match platform_version.drive_abci.structs.platform_state_structure { + 0 => { + let platform_state_v0 = PlatformStateV0::from(v1); + + Ok(platform_state_v0.into()) + } + version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { + method: + "PlatformState::try_from_platform_versioned(PlatformStateForSavingV1)" .to_string(), known_versions: vec![0], received: version, @@ -547,3 +548,24 @@ impl PlatformStateV0Methods for PlatformState { } } } + +#[cfg(test)] +mod tests { + use super::*; + + mod versioned_deserialize { + use super::*; + use crate::test::fixture::platform_state::PLATFORM_STATE_V3_TESTNET; + use platform_version::version::v3::PLATFORM_V3; + use std::ops::Deref; + + #[test] + fn should_deserialize_state_stored_in_version_0_from_testnet() { + let serialized_state = + hex::decode(PLATFORM_STATE_V3_TESTNET.deref()).expect("failed to decode hex"); + + PlatformState::versioned_deserialize(&serialized_state, &PLATFORM_V3) + .expect("failed to deserialize state"); + } + } +} diff --git a/packages/rs-drive-abci/src/platform_types/platform_state/v0/mod.rs b/packages/rs-drive-abci/src/platform_types/platform_state/v0/mod.rs index f9fa9d6deb..d1c2ccd464 100644 --- a/packages/rs-drive-abci/src/platform_types/platform_state/v0/mod.rs +++ b/packages/rs-drive-abci/src/platform_types/platform_state/v0/mod.rs @@ -24,7 +24,11 @@ use crate::platform_types::signature_verification_quorum_set::{ SignatureVerificationQuorumSet, SignatureVerificationQuorumSetForSaving, }; use crate::platform_types::validator_set::v0::ValidatorSetV0Getters; -use dpp::fee::default_costs::CachedEpochIndexFeeVersions; +use dpp::fee::default_costs::{ + CachedEpochIndexFeeVersions, CachedEpochIndexFeeVersionsFieldsBeforeVersion4, + EpochIndexFeeVersionsForStorage, +}; +use dpp::version::fee::FeeVersion; use itertools::Itertools; use std::collections::BTreeMap; use std::fmt::{Debug, Formatter}; @@ -154,15 +158,51 @@ pub struct PlatformStateForSavingV0 { pub hpmn_masternode_list: BTreeMap, /// previous FeeVersions - pub previous_fee_versions: CachedEpochIndexFeeVersions, + pub previous_fee_versions: CachedEpochIndexFeeVersionsFieldsBeforeVersion4, +} + +/// Platform state +#[derive(Clone, Debug, Encode, Decode)] +pub struct PlatformStateForSavingV1 { + /// Information about the genesis block + pub genesis_block_info: Option, + /// Information about the last block + pub last_committed_block_info: Option, + /// Current Version + pub current_protocol_version_in_consensus: ProtocolVersion, + /// upcoming protocol version + pub next_epoch_protocol_version: ProtocolVersion, + /// current quorum + pub current_validator_set_quorum_hash: Bytes32, + /// next quorum + pub next_validator_set_quorum_hash: Option, + /// current validator set quorums + /// The validator set quorums are a subset of the quorums, but they also contain the list of + /// all members + pub validator_sets: Vec<(Bytes32, ValidatorSet)>, + + /// The quorums used for validating chain locks + pub chain_lock_validating_quorums: SignatureVerificationQuorumSetForSaving, + + /// The quorums used for validating instant locks + pub instant_lock_validating_quorums: SignatureVerificationQuorumSetForSaving, + + /// current full masternode list + pub full_masternode_list: BTreeMap, + + /// current HPMN masternode list + pub hpmn_masternode_list: BTreeMap, + + /// previous FeeVersions + pub previous_fee_versions: EpochIndexFeeVersionsForStorage, } -impl TryFrom for PlatformStateForSavingV0 { +impl TryFrom for PlatformStateForSavingV1 { type Error = Error; fn try_from(value: PlatformStateV0) -> Result { let platform_version = value.current_platform_version()?; - Ok(PlatformStateForSavingV0 { + Ok(PlatformStateForSavingV1 { genesis_block_info: value.genesis_block_info, last_committed_block_info: value.last_committed_block_info, current_protocol_version_in_consensus: value.current_protocol_version_in_consensus, @@ -201,7 +241,11 @@ impl TryFrom for PlatformStateForSavingV0 { )) }) .collect::, Error>>()?, - previous_fee_versions: value.previous_fee_versions, + previous_fee_versions: value + .previous_fee_versions + .into_iter() + .map(|(epoch_index, fee_version)| (epoch_index, fee_version.fee_version_number)) + .collect(), }) } } @@ -237,7 +281,57 @@ impl From for PlatformStateV0 { .into_iter() .map(|(k, v)| (ProTxHash::from_byte_array(k.to_buffer()), v.into())) .collect(), - previous_fee_versions: value.previous_fee_versions, + previous_fee_versions: value + .previous_fee_versions + .into_iter() + .map(|(epoch_index, _)| (epoch_index, FeeVersion::first())) + .collect(), + } + } +} + +impl From for PlatformStateV0 { + fn from(value: PlatformStateForSavingV1) -> Self { + PlatformStateV0 { + genesis_block_info: value.genesis_block_info, + last_committed_block_info: value.last_committed_block_info, + current_protocol_version_in_consensus: value.current_protocol_version_in_consensus, + next_epoch_protocol_version: value.next_epoch_protocol_version, + current_validator_set_quorum_hash: QuorumHash::from_byte_array( + value.current_validator_set_quorum_hash.to_buffer(), + ), + next_validator_set_quorum_hash: value + .next_validator_set_quorum_hash + .map(|bytes| QuorumHash::from_byte_array(bytes.to_buffer())), + patched_platform_version: None, + validator_sets: value + .validator_sets + .into_iter() + .map(|(k, v)| (QuorumHash::from_byte_array(k.to_buffer()), v)) + .collect(), + chain_lock_validating_quorums: value.chain_lock_validating_quorums.into(), + instant_lock_validating_quorums: value.instant_lock_validating_quorums.into(), + full_masternode_list: value + .full_masternode_list + .into_iter() + .map(|(k, v)| (ProTxHash::from_byte_array(k.to_buffer()), v.into())) + .collect(), + hpmn_masternode_list: value + .hpmn_masternode_list + .into_iter() + .map(|(k, v)| (ProTxHash::from_byte_array(k.to_buffer()), v.into())) + .collect(), + previous_fee_versions: value + .previous_fee_versions + .into_iter() + .map(|(epoch_index, fee_version_number)| { + ( + epoch_index, + FeeVersion::get(fee_version_number) + .expect("expected fee version number to exist"), + ) + }) + .collect(), } } } diff --git a/packages/rs-drive-abci/src/test/fixture/abci.rs b/packages/rs-drive-abci/src/test/fixture/abci.rs index 26a7803a6e..45abd250ca 100644 --- a/packages/rs-drive-abci/src/test/fixture/abci.rs +++ b/packages/rs-drive-abci/src/test/fixture/abci.rs @@ -3,14 +3,18 @@ use crate::config::PlatformConfig; use dpp::version::PlatformVersion; +use dpp::version::ProtocolVersion; use tenderdash_abci::proto::abci::RequestInitChain; use tenderdash_abci::proto::google::protobuf::Timestamp; use tenderdash_abci::proto::types::{ConsensusParams, VersionParams}; /// Creates static init chain request fixture -pub fn static_init_chain_request(config: &PlatformConfig) -> RequestInitChain { - let platform_version = PlatformVersion::get(config.initial_protocol_version) - .expect("expected to get platform version"); +pub fn static_init_chain_request( + config: &PlatformConfig, + protocol_version: ProtocolVersion, +) -> RequestInitChain { + let platform_version = + PlatformVersion::get(protocol_version).expect("expected to get platform version"); RequestInitChain { time: Some(Timestamp { seconds: 0, @@ -19,7 +23,7 @@ pub fn static_init_chain_request(config: &PlatformConfig) -> RequestInitChain { chain_id: "strategy_tests".to_string(), consensus_params: Some(ConsensusParams { version: Some(VersionParams { - app_version: config.initial_protocol_version as u64, + app_version: protocol_version as u64, consensus_version: platform_version.consensus.tenderdash_consensus_version as i32, }), ..Default::default() diff --git a/packages/rs-drive-abci/src/test/fixture/mod.rs b/packages/rs-drive-abci/src/test/fixture/mod.rs index c52eb0a4c2..4df7078f8c 100644 --- a/packages/rs-drive-abci/src/test/fixture/mod.rs +++ b/packages/rs-drive-abci/src/test/fixture/mod.rs @@ -1 +1,2 @@ pub mod abci; +pub mod platform_state; diff --git a/packages/rs-drive-abci/src/test/fixture/platform_state.rs b/packages/rs-drive-abci/src/test/fixture/platform_state.rs new file mode 100644 index 0000000000..7c8ae424fd --- /dev/null +++ b/packages/rs-drive-abci/src/test/fixture/platform_state.rs @@ -0,0 +1,9 @@ +//! Platform execution state fiixtures +//! + +use std::cell::LazyCell; + +/// Platform execution state v3 from testnet +pub const PLATFORM_STATE_V3_TESTNET: LazyCell<&str> = LazyCell::new(|| { + "00000100fd00000192670b9514fb78b1fc00110ab7fb078b34bbc2a6b045158657746dc5db1105bdd6cb6b28a3adcd8735e91dc2e78d8253000000b91e2a2fe9ab4c3899dc7d2d85c9e00e068603afe59058d5415a84773de28aaaab739907a87bba3ff79428d1c8ef5c2a1f8ae5e8f95dfb32a3e07a767440784f3f9a761c60156f9244a902c0626f8bc8fe003786c70f1fc6be41da467d8a7a96ca935bbc898e4a56cd3865874a44134f0cccff168f01a38d25c03aa3bbfe4234869a8f0e57fbe611139cd6d7ac0a310f08ab1583ed6e70afd63ac3649faff1682184939d0a32f5abf1fbc8eeb487c29332191033d1c156f863c09d34b0000303000000b91e2a2fe9ab4c3899dc7d2d85c9e00e068603afe59058d5415a84773d001820000000f1187cb12e35cb2a20fa7ebaad86a10a07f37a26d91068fcbde0ee462d0020000000f1187cb12e35cb2a20fa7ebaad86a10a07f37a26d91068fcbde0ee462d00fc00110aa8192005b687978344fa2433b2aa99d41f643e2d8581a789cdc23084889ceca5244ea82005b687978344fa2433b2aa99d41f643e2d8581a789cdc23084889ceca5244ea80130b15b76938c54f51b8386980eb3b8631b34ccd35c6884830a43ae3e52ff5a273aa5026d4adf2ebb33cf7c678b72eab8bb0d35322e32342e3132342e313632148feb00404d6f765856c95e587b2523a365bc7258fb4e1ffb05a3fb8f30002012de3ea6678dadb1db529b7fa98762160625055de2aa34e757c93c136233f4a22012de3ea6678dadb1db529b7fa98762160625055de2aa34e757c93c136233f4a201308897e2f392f0e1f2aad3ab24051db60ec4863b99d031c8c8c97b55156547d55cced5bfe08996a05ee652418ea98151870e3231322e32342e3130332e31343914c1161c96de3dae28cd7f20ff8c2aa7b94b866d76fb4e1ffb05a3fb8f300020143dcd6a6b7684fde01e88a10e5d65de9a29244c5ecd586d14a342657025f11320143dcd6a6b7684fde01e88a10e5d65de9a29244c5ecd586d14a342657025f11301308dd61f6d77efbc7a1f689fed01dbab0566c71a2acf19a0d26b19a4c3daa582ca5d21c5e137df714d513bef879f0bdb040d33352e3136342e32332e32343514b5f25f8f70cf8d05c2d2970bdf186c994431d84efb4e1ffb05a3fb8f30002020107ec50e81880dca18178bb7e53e2d0449c0734106a607253b9af2ffea006c2020107ec50e81880dca18178bb7e53e2d0449c0734106a607253b9af2ffea006c0130b661002db656ba258788a2f9af91710a2e91c0d138b2edddde50d651a5173b3f8e248c4c7e22beee609072fc81ac89f30c33352e38352e32312e3137391435d9eb76397d05b43b5cd8da7ccfa8408bc89ab3fb4e1ffb05a3fb8f3000202e48651a2e9c0cb4f2fb7ab874061aa4af0cd28b59695631e6a35af3950ef6fb202e48651a2e9c0cb4f2fb7ab874061aa4af0cd28b59695631e6a35af3950ef6fb0130a3ad85022b69916fa555be50d6b8d77d5b91f8ca72cc91f106b7f4b9fb806478362d5976a34a5e2b9361262e32defff50d35342e3134392e33332e313637141ffbf1d32541dcb8f5555305295704a9ff9adc24fb4e1ffb05a3fb8f3000203971dab9691efac06e4ce7a5483131373e84726458924fe48b7d541791693be1203971dab9691efac06e4ce7a5483131373e84726458924fe48b7d541791693be10130b0a6419f2650de0abe6cefbe8305b31e5cac7cb80f23472036009076904bb40a7282aae4b3fb6025d437813c3619691b0d39322e36332e3137362e3230321461c274080f47a95be5372ef8c69bb60ab1d4ca82fb4e1ffb05a3fb8f30002040784f3f9a761c60156f9244a902c0626f8bc8fe003786c70f1fc6be41da467d2040784f3f9a761c60156f9244a902c0626f8bc8fe003786c70f1fc6be41da467d0130b309f7e2254b0d55fd6e75be528f7b05ed8623dcaf0addf51ff50b13cec0312ec15d00b6394981ef2a9c7fcea3549a9b0c35322e31302e3232392e3131143e8b10646ee9d6c28d75c280b357dd3a9ae9f962fb4e1ffb05a3fb8f3000205b246080ba64350685fe302d3d790f5bb238cb619920d46230c844f079944a23205b246080ba64350685fe302d3d790f5bb238cb619920d46230c844f079944a230130b6f7f4e44b06e8f588473c21d6aa2645b6638eeecdb5f0290889ef7cb3d94b138bd46a4d91b5b56cf9bf96777a13579d0d33352e3136352e35302e31323614f460a07a2b0dc932e1d8ff2dee2b984ac415dcebfb4e1ffb05a3fb8f3000205c6542766615387183715d958a925552472f93335fa1612880423e4bbdaef436205c6542766615387183715d958a925552472f93335fa1612880423e4bbdaef4360130a743d1bf6e3165cb7450b97a907b4b524de83538c85b2110f59bfde026cdce7104c91715e254b77b25175b9c28d8ec9c0d34342e3233392e33392e31353314972a33056d57359de8acfa4fb8b29dc1c14f76b8fb4e1ffb05a3fb8f30002061d33f478933797be4de88353c7c2d843c21310f6d00f6eff31424a756ee7dfb2061d33f478933797be4de88353c7c2d843c21310f6d00f6eff31424a756ee7dfb0130b5286eded79114127ddc14075e3cc71e179f5247c88059e574416224da0e8c2b0cd65f2d1941dc9dfeaa22873e8339880c35322e31322e3137362e3930147ada3e486409b39c94a0833c8d782f35bc24e96afb4e1ffb05a3fb8f3000206d1b185ba036efcd44a77e05a9aaf69a0c4e40976aec00b04773e52863320966206d1b185ba036efcd44a77e05a9aaf69a0c4e40976aec00b04773e5286332096601308261037fde2ea2c99bc904ae23c6cb827177aa9dbc70119e1cffa0716681f0e92da1639df91d91c6fd194c128a8add900e34342e3232382e3234322e31383114c374f016ea61e76aab79b8bb95a1ba0e6e3eee6ffb4e1ffb05a3fb8f3000207135069642e1a72807a383fb5a14b9af6758292fee53fe2a7f7ac6f528bf7019207135069642e1a72807a383fb5a14b9af6758292fee53fe2a7f7ac6f528bf7019013099d894f15fd6a36a44f56a48502b6da8315ce203e8b7908105eab9fcf1e8fca01ee40bbf1a67a2828541a0da9e3d21fb0d35342e3138392e3136342e333914f9956e70daffa263e8cf29fa6557b7b630a595a8fb4e1ffb05a3fb8f300020754b89dae8db20fc4cee5e3adb07b146d7efe508a66fa0a8e1094675b9daa35e20754b89dae8db20fc4cee5e3adb07b146d7efe508a66fa0a8e1094675b9daa35e0130a8a91ee2617de812f7f1cc2c4fbbf2cea408edaf225a8da74761f6ca6cbed60b2054ff1730f54298e82af67d888042470c34342e3233332e34342e39351446d938862af6d9a291e26c0048177db2892a710bfb4e1ffb05a3fb8f3000207718edad371e46d20fad30086e4acf4a05c2b660df6ae5f2a684aebdf1be4290207718edad371e46d20fad30086e4acf4a05c2b660df6ae5f2a684aebdf1be42900130b2631ef598d8bebfbcb40b6653250d25d07e42be82709160b1d01e4d3e59af5c3be2262d88ee86c91385ba3b35ce15b10d34342e3232372e3133372e3737140498ade3c80045c2a7520e921180ae1c39da5c57fb4e1ffb05a3fb8f30002085f15a31d3838293a9c1d72a1a0fa21e66110ce20878bd4c1024c4ae1d5be8242085f15a31d3838293a9c1d72a1a0fa21e66110ce20878bd4c1024c4ae1d5be8240130b84771f8c123270fcee41986222050294edde00dbbc2abdb2e24dfdcbed36383ea34261eecdf4684e9be3339c235a44c0d35342e3230312e33322e3133311468c506d43816d1a8389c860c1d162be44d1e777cfb4e1ffb05a3fb8f3000208de8b12952f7058d827bd04cdff1c2175d87bbf89f28b52452a637bc979addc4208de8b12952f7058d827bd04cdff1c2175d87bbf89f28b52452a637bc979addc40130961e707780b035e2bf7d82ad6a98a82b81615d31129f9be4a43b7ac0e91a7a4f408836b1a067605bc4cb8bb1699c8d190c35322e34332e38362e32333114337b7fb5d2c531825c3e0123ac3354018085b302fb4e1ffb05a3fb8f3000208eca4bcbb3a124ab283afd42dad3bdb2077b3809659788a0f1daffce5b9f001f208eca4bcbb3a124ab283afd42dad3bdb2077b3809659788a0f1daffce5b9f001f0130ae4d8adbece1973d8625d725a644a1dbeb36dcda498040abc45392caa46f515be917ea83400be5342cad96304dc321460d35342e36382e3233352e32303114c075993a8336f93a13bb7bbb7e0e89928be4aafbfb4e1ffb05a3fb8f3000209712e85d660fa2f761f980ef5812c225f33f336f285728803dcd421937d3df54209712e85d660fa2f761f980ef5812c225f33f336f285728803dcd421937d3df540130ab0a7879ee8ad513c0633490d3e86ab2645ff07701f24cd887b9f3bcf1c38baef517a76b2641d0fa47f0be61d368b5d20d33352e38322e3139372e31393714ed1131823bcea23ac78af8c01e4d24683d6ecf88fb4e1ffb05a3fb8f30002098ef58c338a0a68e4f2f1d1ee9eb05fcafbb9177d192dac0f698d3d9ba0920962098ef58c338a0a68e4f2f1d1ee9eb05fcafbb9177d192dac0f698d3d9ba09209601308bd3c1a90462ec65d5df7e3e8f93b67f57e174c1c272d7a33bf6faabc28daccd899f88e208379378be95ac500d7713570c34342e3233322e3139362e3614d6ece912cbf02627a4efc3dd37e6833cf3671551fb4e1ffb05a3fb8f3000209cb04f271ba050132c00cc5838fb69e77bc55b5689f9d2d850dc528935f8145c209cb04f271ba050132c00cc5838fb69e77bc55b5689f9d2d850dc528935f8145c01308b10630f61ec66b84180ad865634e62a22448b595d8f1876da42c87dcc63c5601f393fccfed6bfb17cbe0c0db125c86a0c33342e3231342e34382e36381462e960a3f6b650feed98a266b3ccdf6e363562cffb4e1ffb05a3fb8f300020ba8ce1dc72857b4168e33272571df7fbaf84c316dfe48217addcf6595e25421620ba8ce1dc72857b4168e33272571df7fbaf84c316dfe48217addcf6595e2542160130a668ab57cd5700686114d03df153295640e5939144d84fb386ee9811ac459cc48876013df04ad44cca5d27461492e95b0d35322e34322e3230322e3132381462e0104ce0aafc1f06bde37c73702fe84b307f05fb4e1ffb05a3fb8f300020c11c1168dcf9479475cb1355855e30ea75c0cdda8a8f9ea80591568dd1c33ba820c11c1168dcf9479475cb1355855e30ea75c0cdda8a8f9ea80591568dd1c33ba8013094ea96483a36db9fb9647a2fbaf2bf3df39a9e375ae7a8a8b81c71d4ef5e33f704e69ad50d20ca9a1164484ffd5289a00d35342e3231332e3230342e383514fdae7cdf38811659ce9481975b326a5d07236bc5fb4e1ffb05a3fb8f300020d9b090cfc19caf2e27d512e69c43812a274bdf29c081d0ade4fd272ad56a5f8920d9b090cfc19caf2e27d512e69c43812a274bdf29c081d0ade4fd272ad56a5f8901308ceddd73271ab74091fe496bea3786f10d49b68eeb5357300fd5e71c295b726666da80631ad29a5d7cee5ff9eba6b1e10d34342e3234302e39382e313032147034f0d3853c5351fb8e0ffd3c1daf12c51c2d89fb4e1ffb05a3fb8f300020f6496d3c0ac1ad94ff5e3aab2edcabc1c8ba3fbfea0ef3026e90ba786399038120f6496d3c0ac1ad94ff5e3aab2edcabc1c8ba3fbfea0ef3026e90ba78639903810130adef1c638134ebeb1fe996643698f056c4f0c90c2f122d70dbdccc83abc04f9c558d9dd95084443f3c238c0ecff2977b0d35322e31332e3235302e31383214fe2d4798df3e9b41a6823bc0b3f020478e87925dfb4e1ffb05a3fb8f300020ff261d2c1c76907a2ad8aeb6c5611796f03b5cbd88ae92452a4727e13f4f4ac920ff261d2c1c76907a2ad8aeb6c5611796f03b5cbd88ae92452a4727e13f4f4ac90130a9b37ba5ebf8695acb31339b2200e7b34881d809654003fb2845e48e24819cfaae2833da5fec3547d51869acaef931290d35342e3138372e31342e3233321467e05b1b52c7c896adf20035036fe1d30dcefc9cfb4e1ffb05a3fb8f300030a6cbd47ba3201352f0e23d2434f83e1e2029b2514e7273280f9c0a746ce81624e99290d62ddd96097068ef7999d326e4200000004689a842c049d460ee314df1bbfa36530ff86632142fe3b6eee824003400200000004689a842c049d460ee314df1bbfa36530ff86632142fe3b6eee824003400fc00110a90192005b687978344fa2433b2aa99d41f643e2d8581a789cdc23084889ceca5244ea82005b687978344fa2433b2aa99d41f643e2d8581a789cdc23084889ceca5244ea8013084d7ad239563f639a16a9cdb055a81e683f2a0c654f882c9a54d38c2bc10c110da7829f313e9f4b2c70651207cb273110d35322e32342e3132342e313632148feb00404d6f765856c95e587b2523a365bc7258fb4e1ffb05a3fb8f30002012de3ea6678dadb1db529b7fa98762160625055de2aa34e757c93c136233f4a22012de3ea6678dadb1db529b7fa98762160625055de2aa34e757c93c136233f4a201308942b5fe5ab5b6636bc0ebfff21dc7a21f0397cc2ea9362e9b476b10b5668aae608dbf5f1ece54a479747634d74041ea0e3231322e32342e3130332e31343914c1161c96de3dae28cd7f20ff8c2aa7b94b866d76fb4e1ffb05a3fb8f300020143dcd6a6b7684fde01e88a10e5d65de9a29244c5ecd586d14a342657025f11320143dcd6a6b7684fde01e88a10e5d65de9a29244c5ecd586d14a342657025f113013084cd7e8744a28e4036feedf3b6f3d691c8ea21e8e69f0c862215e51a15a51205799f0fa0516c7b7cf02b691dca89d2f50d33352e3136342e32332e32343514b5f25f8f70cf8d05c2d2970bdf186c994431d84efb4e1ffb05a3fb8f30002020107ec50e81880dca18178bb7e53e2d0449c0734106a607253b9af2ffea006c2020107ec50e81880dca18178bb7e53e2d0449c0734106a607253b9af2ffea006c01308de99ca88d7256389dd5c27ac00b98b95bbead6c7b3008fd8dc6bdaec9f4fe1110f7ffe0fc7ad40aefa37919df04968d0c33352e38352e32312e3137391435d9eb76397d05b43b5cd8da7ccfa8408bc89ab3fb4e1ffb05a3fb8f3000202e48651a2e9c0cb4f2fb7ab874061aa4af0cd28b59695631e6a35af3950ef6fb202e48651a2e9c0cb4f2fb7ab874061aa4af0cd28b59695631e6a35af3950ef6fb0130aaf815d4d59789b72527426251177acf276c39c3113810b9e6614fc866ae21a3f65cbde04edccd8bf791940b73fa84ea0d35342e3134392e33332e313637141ffbf1d32541dcb8f5555305295704a9ff9adc24fb4e1ffb05a3fb8f30002040784f3f9a761c60156f9244a902c0626f8bc8fe003786c70f1fc6be41da467d2040784f3f9a761c60156f9244a902c0626f8bc8fe003786c70f1fc6be41da467d0130a4cad187d6efd489b5bac71f56ec6b91e8ed6965bbdd4bebe898678716ddc8a6b7d4e6a0a6fa17bc91a4c1c16d1e64930c35322e31302e3232392e3131143e8b10646ee9d6c28d75c280b357dd3a9ae9f962fb4e1ffb05a3fb8f3000205b246080ba64350685fe302d3d790f5bb238cb619920d46230c844f079944a23205b246080ba64350685fe302d3d790f5bb238cb619920d46230c844f079944a230130b222d9014e083f3b542bae5c3daaa94ab024b602e39e045a279d101c128214d1a7d9742e8afa7a6140de6ad61eaf421a0d33352e3136352e35302e31323614f460a07a2b0dc932e1d8ff2dee2b984ac415dcebfb4e1ffb05a3fb8f30002061d33f478933797be4de88353c7c2d843c21310f6d00f6eff31424a756ee7dfb2061d33f478933797be4de88353c7c2d843c21310f6d00f6eff31424a756ee7dfb0130aa2538b75155fe0304fde0c908be3deacc9abae62bcc0e0336f9cc0c24583d55ff3959963affeb7afcf2a6a0bd6d61410c35322e31322e3137362e3930147ada3e486409b39c94a0833c8d782f35bc24e96afb4e1ffb05a3fb8f3000206d1b185ba036efcd44a77e05a9aaf69a0c4e40976aec00b04773e52863320966206d1b185ba036efcd44a77e05a9aaf69a0c4e40976aec00b04773e52863320966013099f0aa551bd2df9baf3eb6adf0261df8a749a9413f62dd8473fd6ab03b3a6917157a1b5d3b01307d4b32d65fd495be8f0e34342e3232382e3234322e31383114c374f016ea61e76aab79b8bb95a1ba0e6e3eee6ffb4e1ffb05a3fb8f3000207718edad371e46d20fad30086e4acf4a05c2b660df6ae5f2a684aebdf1be4290207718edad371e46d20fad30086e4acf4a05c2b660df6ae5f2a684aebdf1be429001308a81e53c43f6ecb09730e937d44984c697938ad776c58424eb626580507642977097ce8daee7ca61e0e8e052fcc44a820d34342e3232372e3133372e3737140498ade3c80045c2a7520e921180ae1c39da5c57fb4e1ffb05a3fb8f30002087075234ac47353b42bb97ce46330cb67cd4648c01f0b2393d7e729b0d6789182087075234ac47353b42bb97ce46330cb67cd4648c01f0b2393d7e729b0d6789180130b361d2179cadf86c3d4788078a5380afe844c3b354a4336a35ef6fb774a565f3c1319e597841f87182d6dbce0527ec180e33352e3136372e3134352e313439149b9cdbfe3568cc0b37f136b00a634c75653f05e3fb4e1ffb05a3fb8f3000208917bb546318f3410d1a7901c7b846a73446311b5164b45a03f0e613f208f234208917bb546318f3410d1a7901c7b846a73446311b5164b45a03f0e613f208f2340130aa71b13016a1a1fee60d1db3d6987aafcbb813e7cb4ade9766f0b9ea92a89eaefbf540af24d4b7fd021565041edd1ade0d35322e31332e3133322e313436145bdbf34a0dad860c6ec71523ae39373325225cc1fb4e1ffb05a3fb8f3000208b8d1193afd22e538ce0c9fb50fee155d0f6176ca68e65da684c5dce2d1e0815208b8d1193afd22e538ce0c9fb50fee155d0f6176ca68e65da684c5dce2d1e08150130b886ecda081643bc5e24dfe7d0403bd2639afebf056cbde277b5558e2d497837f26c0acc02d3742e298c5e8ad3f83a650c35322e33342e3134342e353014a0a0e17bfe82a484fefe348b7569a6d77d29d2c2fb4e1ffb05a3fb8f3000208de8b12952f7058d827bd04cdff1c2175d87bbf89f28b52452a637bc979addc4208de8b12952f7058d827bd04cdff1c2175d87bbf89f28b52452a637bc979addc4013091b43a2470e00f9aa20ca5f759bfc2181a9822830f057c299ed9f5324f5266c7f3fbc934a4a20baa9a01563a12632fc60c35322e34332e38362e32333114337b7fb5d2c531825c3e0123ac3354018085b302fb4e1ffb05a3fb8f3000208eca4bcbb3a124ab283afd42dad3bdb2077b3809659788a0f1daffce5b9f001f208eca4bcbb3a124ab283afd42dad3bdb2077b3809659788a0f1daffce5b9f001f0130b35c64527fbc2578fd2723311fe76a4ef602f9314596f9133a2626aa2bd818a828d067946799b3150e25324e0e77e4790d35342e36382e3233352e32303114c075993a8336f93a13bb7bbb7e0e89928be4aafbfb4e1ffb05a3fb8f30002091bbce94c34ebde0d099c0a2cb7635c0c31425ebabcec644f4f1a0854bfa605d2091bbce94c34ebde0d099c0a2cb7635c0c31425ebabcec644f4f1a0854bfa605d01308b8a33b1554491346591a0147b376489af1adac664b6a0b2b4c542627553429c6dfde43048681ae55cd12ea84806fa880c35322e34302e3231392e34311402aa69f8ef6666e7cad6d9323755a0ef3c1b6bd9fb4e1ffb05a3fb8f3000209712e85d660fa2f761f980ef5812c225f33f336f285728803dcd421937d3df54209712e85d660fa2f761f980ef5812c225f33f336f285728803dcd421937d3df54013099cc490e6796af6a93c03be74e46603ee8d597a40c53fee0ef58cde0dd5c70526c6da8b633d2f231d4a1b6ab12329e330d33352e38322e3139372e31393714ed1131823bcea23ac78af8c01e4d24683d6ecf88fb4e1ffb05a3fb8f30002098ef58c338a0a68e4f2f1d1ee9eb05fcafbb9177d192dac0f698d3d9ba0920962098ef58c338a0a68e4f2f1d1ee9eb05fcafbb9177d192dac0f698d3d9ba092096013097309058064a4efd3dac7d1f83e0c9acaf820cc26be3844e38260203eb9de1ab343b85663df57db01030231a58fe51300c34342e3233322e3139362e3614d6ece912cbf02627a4efc3dd37e6833cf3671551fb4e1ffb05a3fb8f3000209cb04f271ba050132c00cc5838fb69e77bc55b5689f9d2d850dc528935f8145c209cb04f271ba050132c00cc5838fb69e77bc55b5689f9d2d850dc528935f8145c013091408bdb75e94dcd5f529e04d40e1338cdd59105e20f644f30035345bd8a1abb4f26a30ed33a5f718fc0651d5e3ea17e0c33342e3231342e34382e36381462e960a3f6b650feed98a266b3ccdf6e363562cffb4e1ffb05a3fb8f300020b3b5748571b60fe9ad112715d6a51725d6e5a52a9c3af5fd36a1724cf50d862f20b3b5748571b60fe9ad112715d6a51725d6e5a52a9c3af5fd36a1724cf50d862f0130804761ed1300c056087c87255d97a6163b5583f9db147b4c13a302783e03ccb91b9c41bd85b5749e6ac1cd66618ee2c80b35322e34332e31332e39321441b308f737ca9e39f67b553158903198a88c516efb4e1ffb05a3fb8f300020ba8ce1dc72857b4168e33272571df7fbaf84c316dfe48217addcf6595e25421620ba8ce1dc72857b4168e33272571df7fbaf84c316dfe48217addcf6595e2542160130b18bb95e55a3159681810e3bba2d820554605bbe094863d2175a58a729ccb5d5c4005668ad5e1568a5a4e6fc9e44868a0d35322e34322e3230322e3132381462e0104ce0aafc1f06bde37c73702fe84b307f05fb4e1ffb05a3fb8f300020c11c1168dcf9479475cb1355855e30ea75c0cdda8a8f9ea80591568dd1c33ba820c11c1168dcf9479475cb1355855e30ea75c0cdda8a8f9ea80591568dd1c33ba80130ac27a016518e3768ba8fdcb01af7a6c3668e2594d90f2d199491cd82b4bd1b8f46f869aa9ca3b82c592360222cded8690d35342e3231332e3230342e383514fdae7cdf38811659ce9481975b326a5d07236bc5fb4e1ffb05a3fb8f300020d9b090cfc19caf2e27d512e69c43812a274bdf29c081d0ade4fd272ad56a5f8920d9b090cfc19caf2e27d512e69c43812a274bdf29c081d0ade4fd272ad56a5f890130aaab1fef4dd9ec25e263524b62b04151d74a51f94bd0bd1d96a69ec372827c0c4e5a3f157e6bcbc5bc9c8f52119e670b0d34342e3234302e39382e313032147034f0d3853c5351fb8e0ffd3c1daf12c51c2d89fb4e1ffb05a3fb8f300020f6496d3c0ac1ad94ff5e3aab2edcabc1c8ba3fbfea0ef3026e90ba786399038120f6496d3c0ac1ad94ff5e3aab2edcabc1c8ba3fbfea0ef3026e90ba78639903810130a3eb4ba1d46723c1321ae975611049a27cffa5de8a9d86348c8f8e00432f515b71e6846a26c466d559db3d0fb24bc70a0d35322e31332e3235302e31383214fe2d4798df3e9b41a6823bc0b3f020478e87925dfb4e1ffb05a3fb8f300020ff261d2c1c76907a2ad8aeb6c5611796f03b5cbd88ae92452a4727e13f4f4ac920ff261d2c1c76907a2ad8aeb6c5611796f03b5cbd88ae92452a4727e13f4f4ac9013093fecca26bf5ad7a125463e41ec77a3e3fc962672fd71ae5982bfb3c0b0dda2276c9a8df4b42795034bf6642c9043b140d35342e3138372e31342e3233321467e05b1b52c7c896adf20035036fe1d30dcefc9cfb4e1ffb05a3fb8f300030b3c85502f9c7789d7ce97199d4b411ee93a771c0209bc6a6b61e3b637eb8f2de1778f8a9c2bbd18ef27a07ac2b7f2121200000010832789d4cdff3cc8a63fad668ccac708af7433c42e189ada6c6e5e66e00200000010832789d4cdff3cc8a63fad668ccac708af7433c42e189ada6c6e5e66e00fc00110a78192005b687978344fa2433b2aa99d41f643e2d8581a789cdc23084889ceca5244ea82005b687978344fa2433b2aa99d41f643e2d8581a789cdc23084889ceca5244ea80130a9f8fc1cbb8413542a88a12c2bd8ed37d164176e3ec69ef1da36b17732e9edfe26d5a4637b714871c0969e85c5ed49340d35322e32342e3132342e313632148feb00404d6f765856c95e587b2523a365bc7258fb4e1ffb05a3fb8f300020143dcd6a6b7684fde01e88a10e5d65de9a29244c5ecd586d14a342657025f11320143dcd6a6b7684fde01e88a10e5d65de9a29244c5ecd586d14a342657025f1130130b77c254aa8967f93938cccda412ff4cc2ae33c1632fdf22d6d6e01e350bee7cda4293fcf7bdd08421a89d89d31f3d3700d33352e3136342e32332e32343514b5f25f8f70cf8d05c2d2970bdf186c994431d84efb4e1ffb05a3fb8f30002020107ec50e81880dca18178bb7e53e2d0449c0734106a607253b9af2ffea006c2020107ec50e81880dca18178bb7e53e2d0449c0734106a607253b9af2ffea006c0130a95cfa0fb3e2b7405577f766f10f8a527b4f0ea8da4fd9e308eaef910c82b6bfe395ebac71d7344db812de815e0b7a6e0c33352e38352e32312e3137391435d9eb76397d05b43b5cd8da7ccfa8408bc89ab3fb4e1ffb05a3fb8f3000203971dab9691efac06e4ce7a5483131373e84726458924fe48b7d541791693be1203971dab9691efac06e4ce7a5483131373e84726458924fe48b7d541791693be10130972fa1195e580291865db0045df4ca36e3775c91bc14107259ecde0fbbabaa90c965949a00cd11e9a7c288d9b325edb00d39322e36332e3137362e3230321461c274080f47a95be5372ef8c69bb60ab1d4ca82fb4e1ffb05a3fb8f30002039741ad83dd791e1e738f19edae82d6c0322972e6a455981424da3769b3dbd4a2039741ad83dd791e1e738f19edae82d6c0322972e6a455981424da3769b3dbd4a01308ce9094c3230172b326a5ee57a2f76413371a66bda5c34c6ef0f0f62cef8fab9fa44b9423c182ca2e8779d17b77bb14a0e33352e3136332e3134342e32333014ec7bf3b9bc72eda38c80bb7cf16e294e763e56b4fb4e1ffb05a3fb8f30002040784f3f9a761c60156f9244a902c0626f8bc8fe003786c70f1fc6be41da467d2040784f3f9a761c60156f9244a902c0626f8bc8fe003786c70f1fc6be41da467d0130b5b6cda330445e2e8ae0289b476aab0b925f0f6f62975c2af939512ab2ecb00a669a099c9d1a9f3b1c322eed82a0a6430c35322e31302e3232392e3131143e8b10646ee9d6c28d75c280b357dd3a9ae9f962fb4e1ffb05a3fb8f3000205b246080ba64350685fe302d3d790f5bb238cb619920d46230c844f079944a23205b246080ba64350685fe302d3d790f5bb238cb619920d46230c844f079944a230130a99d91eda26d9a436188ecfce2df4f7afc9954764a421234713f1083fd445abd9733e0b8bbf0e6fe43db02cfa07fb11f0d33352e3136352e35302e31323614f460a07a2b0dc932e1d8ff2dee2b984ac415dcebfb4e1ffb05a3fb8f3000205c6542766615387183715d958a925552472f93335fa1612880423e4bbdaef436205c6542766615387183715d958a925552472f93335fa1612880423e4bbdaef43601308c2bf1a5c7782b57c78edc0c9a780bb03fd12b563b43cdf7f0b1e1e96081f8d11d3e131988f37ebe2799eaaedbd065c40d34342e3233392e33392e31353314972a33056d57359de8acfa4fb8b29dc1c14f76b8fb4e1ffb05a3fb8f3000206d1b185ba036efcd44a77e05a9aaf69a0c4e40976aec00b04773e52863320966206d1b185ba036efcd44a77e05a9aaf69a0c4e40976aec00b04773e528633209660130a2a5775aec8818a7914b1a610d095343e5e54e3834a51fe0c2c8b0d85e5e347bbc205a2cc19d665da624996f5c797a520e34342e3232382e3234322e31383114c374f016ea61e76aab79b8bb95a1ba0e6e3eee6ffb4e1ffb05a3fb8f3000207135069642e1a72807a383fb5a14b9af6758292fee53fe2a7f7ac6f528bf7019207135069642e1a72807a383fb5a14b9af6758292fee53fe2a7f7ac6f528bf70190130b2613f4f71b8cb2d6d5d40312bb676bf0272fcb4d141e2aa23dfe8698655a4c1c93150b244488a13f5cf60dc3301c1830d35342e3138392e3136342e333914f9956e70daffa263e8cf29fa6557b7b630a595a8fb4e1ffb05a3fb8f300020754b89dae8db20fc4cee5e3adb07b146d7efe508a66fa0a8e1094675b9daa35e20754b89dae8db20fc4cee5e3adb07b146d7efe508a66fa0a8e1094675b9daa35e0130ae815e003eeb65606f18a624ca248f83c1a70c168b15a75d935127fa479ba75a30d734d40b008c4f26e6b384957837fc0c34342e3233332e34342e39351446d938862af6d9a291e26c0048177db2892a710bfb4e1ffb05a3fb8f3000207718edad371e46d20fad30086e4acf4a05c2b660df6ae5f2a684aebdf1be4290207718edad371e46d20fad30086e4acf4a05c2b660df6ae5f2a684aebdf1be42900130b0b9f5db3633b48d5359d5b8d9e99f2eaf5e6603fae01746602f538e8d9e923ff1f47a5f84ff0be24d24d6e80d2710df0d34342e3232372e3133372e3737140498ade3c80045c2a7520e921180ae1c39da5c57fb4e1ffb05a3fb8f30002087075234ac47353b42bb97ce46330cb67cd4648c01f0b2393d7e729b0d6789182087075234ac47353b42bb97ce46330cb67cd4648c01f0b2393d7e729b0d6789180130a36373377b1befa6f35aec8f2c56b95433324e2526748116338d7cda1274090cca1c69959b02e3f9c97a1787798e05ac0e33352e3136372e3134352e313439149b9cdbfe3568cc0b37f136b00a634c75653f05e3fb4e1ffb05a3fb8f3000208917bb546318f3410d1a7901c7b846a73446311b5164b45a03f0e613f208f234208917bb546318f3410d1a7901c7b846a73446311b5164b45a03f0e613f208f2340130ab3ac53a601829b7d999c55095069f25b6df87616d2276386b3eb28c68a861ce46352a008ce967f2a9b68c06a41cab1a0d35322e31332e3133322e313436145bdbf34a0dad860c6ec71523ae39373325225cc1fb4e1ffb05a3fb8f3000208b8d1193afd22e538ce0c9fb50fee155d0f6176ca68e65da684c5dce2d1e0815208b8d1193afd22e538ce0c9fb50fee155d0f6176ca68e65da684c5dce2d1e08150130a42e3e2fdf2fe5c7f368e695f0649831a6817d8670f895c9b1475836a284ae985703ef520b369adff6a4fc00edc4cfff0c35322e33342e3134342e353014a0a0e17bfe82a484fefe348b7569a6d77d29d2c2fb4e1ffb05a3fb8f3000208de8b12952f7058d827bd04cdff1c2175d87bbf89f28b52452a637bc979addc4208de8b12952f7058d827bd04cdff1c2175d87bbf89f28b52452a637bc979addc40130a1172e43ca64a94af9ebc84191b9a8d071c4ef72f2d20a1d4982753e6a875821784dfd5b81f9670fd3c88ba79bfd74800c35322e34332e38362e32333114337b7fb5d2c531825c3e0123ac3354018085b302fb4e1ffb05a3fb8f3000208e11eb784883d3dc9d0d74a74633f067dc61c408dfdee49b8f93bb161f2916c0208e11eb784883d3dc9d0d74a74633f067dc61c408dfdee49b8f93bb161f2916c00130b9f7bdfe0077e3a924a4d881683a3a51aa4204329451ce160c83c78a908eae5614e965220e26daff6894bcad781c06250c35322e38392e3135342e3438146d57707c196e06487d326094c964f258f5b77c35fb4e1ffb05a3fb8f3000209712e85d660fa2f761f980ef5812c225f33f336f285728803dcd421937d3df54209712e85d660fa2f761f980ef5812c225f33f336f285728803dcd421937d3df5401309362f6b7585fe368cd6e82e0ac831ebfb04d65663a3f997db0c55b6397e73565f691f4968ba9e60418b94f6e1b8466430d33352e38322e3139372e31393714ed1131823bcea23ac78af8c01e4d24683d6ecf88fb4e1ffb05a3fb8f30002098ef58c338a0a68e4f2f1d1ee9eb05fcafbb9177d192dac0f698d3d9ba0920962098ef58c338a0a68e4f2f1d1ee9eb05fcafbb9177d192dac0f698d3d9ba0920960130a8f426b9e58b4448cb7fcc01f05196567b7cca3ae0b601dbe096853916cab1c4c3e6e77fb59d0e944d5546fb3e74099e0c34342e3233322e3139362e3614d6ece912cbf02627a4efc3dd37e6833cf3671551fb4e1ffb05a3fb8f3000209cb04f271ba050132c00cc5838fb69e77bc55b5689f9d2d850dc528935f8145c209cb04f271ba050132c00cc5838fb69e77bc55b5689f9d2d850dc528935f8145c013088e2df5210ce24801f4fd9fed061152862ac4bf8209ce7a9635581d9e204ad2aca8dac837a392f2e692fffd2bd18d8890c33342e3231342e34382e36381462e960a3f6b650feed98a266b3ccdf6e363562cffb4e1ffb05a3fb8f300020b3b5748571b60fe9ad112715d6a51725d6e5a52a9c3af5fd36a1724cf50d862f20b3b5748571b60fe9ad112715d6a51725d6e5a52a9c3af5fd36a1724cf50d862f0130a3079ebff53a2eaa226c29515eb1f2f83c32a9f8730c1cfd22af38823153046ec09afdd6439b21de4c0ec7943e3ff5640b35322e34332e31332e39321441b308f737ca9e39f67b553158903198a88c516efb4e1ffb05a3fb8f300020bbfd0ac1977011267a7032641ef5487fe15a4de798faa485b156fb3b7eb0acb820bbfd0ac1977011267a7032641ef5487fe15a4de798faa485b156fb3b7eb0acb80130b6083baad99daa8ef067cbaa396436591c52f338cb89ecdf76ab9804c4b02ee9934df13205c483167edaaf446609e6420c33352e38322e34392e31393614dbbebbc52a5bae21b818e0487311041c91b2683bfb4e1ffb05a3fb8f300020c11c1168dcf9479475cb1355855e30ea75c0cdda8a8f9ea80591568dd1c33ba820c11c1168dcf9479475cb1355855e30ea75c0cdda8a8f9ea80591568dd1c33ba80130a87180e5349d3e6f9472bf19021fb38c8363b36d53feae8f57754e68676b2ba1ceb7680879981cb63fbf51c8f96323790d35342e3231332e3230342e383514fdae7cdf38811659ce9481975b326a5d07236bc5fb4e1ffb05a3fb8f300020d9b090cfc19caf2e27d512e69c43812a274bdf29c081d0ade4fd272ad56a5f8920d9b090cfc19caf2e27d512e69c43812a274bdf29c081d0ade4fd272ad56a5f890130a5b8be704d75fba99633db0e207603eacf3fc51a77b15d3f73ce6b75de19dcce4b5a3ca86b247b1414cb13bfd21d67c80d34342e3234302e39382e313032147034f0d3853c5351fb8e0ffd3c1daf12c51c2d89fb4e1ffb05a3fb8f300020f6496d3c0ac1ad94ff5e3aab2edcabc1c8ba3fbfea0ef3026e90ba786399038120f6496d3c0ac1ad94ff5e3aab2edcabc1c8ba3fbfea0ef3026e90ba786399038101308ed36f99ba583e180b66367374229462d8f7826abbff8c3422107d5c17a2c624bd3a154c0eae0e44f3f56d06b4da4d0e0d35322e31332e3235302e31383214fe2d4798df3e9b41a6823bc0b3f020478e87925dfb4e1ffb05a3fb8f300030b10b6159372531cd813094527b17eef8a077d4300503c6fc147e07abb40ed05a32fcfdd166e91d1c54a388d0d0f5df4f2000000072da33f586cdd86a566cb30268f411dad855dc3fd18c5669410c7cdaea002000000072da33f586cdd86a566cb30268f411dad855dc3fd18c5669410c7cdaea00fc00110a60192012de3ea6678dadb1db529b7fa98762160625055de2aa34e757c93c136233f4a22012de3ea6678dadb1db529b7fa98762160625055de2aa34e757c93c136233f4a2000e3231322e32342e3130332e31343914c1161c96de3dae28cd7f20ff8c2aa7b94b866d76fb4e1ffb05a3fb8f300020143dcd6a6b7684fde01e88a10e5d65de9a29244c5ecd586d14a342657025f11320143dcd6a6b7684fde01e88a10e5d65de9a29244c5ecd586d14a342657025f113000d33352e3136342e32332e32343514b5f25f8f70cf8d05c2d2970bdf186c994431d84efb4e1ffb05a3fb8f30002020107ec50e81880dca18178bb7e53e2d0449c0734106a607253b9af2ffea006c2020107ec50e81880dca18178bb7e53e2d0449c0734106a607253b9af2ffea006c000c33352e38352e32312e3137391435d9eb76397d05b43b5cd8da7ccfa8408bc89ab3fb4e1ffb05a3fb8f3000202e48651a2e9c0cb4f2fb7ab874061aa4af0cd28b59695631e6a35af3950ef6fb202e48651a2e9c0cb4f2fb7ab874061aa4af0cd28b59695631e6a35af3950ef6fb000d35342e3134392e33332e313637141ffbf1d32541dcb8f5555305295704a9ff9adc24fb4e1ffb05a3fb8f3000203971dab9691efac06e4ce7a5483131373e84726458924fe48b7d541791693be1203971dab9691efac06e4ce7a5483131373e84726458924fe48b7d541791693be1000d39322e36332e3137362e3230321461c274080f47a95be5372ef8c69bb60ab1d4ca82fb4e1ffb05a3fb8f30002039741ad83dd791e1e738f19edae82d6c0322972e6a455981424da3769b3dbd4a2039741ad83dd791e1e738f19edae82d6c0322972e6a455981424da3769b3dbd4a000e33352e3136332e3134342e32333014ec7bf3b9bc72eda38c80bb7cf16e294e763e56b4fb4e1ffb05a3fb8f3000205c6542766615387183715d958a925552472f93335fa1612880423e4bbdaef436205c6542766615387183715d958a925552472f93335fa1612880423e4bbdaef436000d34342e3233392e33392e31353314972a33056d57359de8acfa4fb8b29dc1c14f76b8fb4e1ffb05a3fb8f30002061d33f478933797be4de88353c7c2d843c21310f6d00f6eff31424a756ee7dfb2061d33f478933797be4de88353c7c2d843c21310f6d00f6eff31424a756ee7dfb000c35322e31322e3137362e3930147ada3e486409b39c94a0833c8d782f35bc24e96afb4e1ffb05a3fb8f3000206d1b185ba036efcd44a77e05a9aaf69a0c4e40976aec00b04773e52863320966206d1b185ba036efcd44a77e05a9aaf69a0c4e40976aec00b04773e52863320966000e34342e3232382e3234322e31383114c374f016ea61e76aab79b8bb95a1ba0e6e3eee6ffb4e1ffb05a3fb8f3000207135069642e1a72807a383fb5a14b9af6758292fee53fe2a7f7ac6f528bf7019207135069642e1a72807a383fb5a14b9af6758292fee53fe2a7f7ac6f528bf7019000d35342e3138392e3136342e333914f9956e70daffa263e8cf29fa6557b7b630a595a8fb4e1ffb05a3fb8f300020754b89dae8db20fc4cee5e3adb07b146d7efe508a66fa0a8e1094675b9daa35e20754b89dae8db20fc4cee5e3adb07b146d7efe508a66fa0a8e1094675b9daa35e000c34342e3233332e34342e39351446d938862af6d9a291e26c0048177db2892a710bfb4e1ffb05a3fb8f30002085f15a31d3838293a9c1d72a1a0fa21e66110ce20878bd4c1024c4ae1d5be8242085f15a31d3838293a9c1d72a1a0fa21e66110ce20878bd4c1024c4ae1d5be824000d35342e3230312e33322e3133311468c506d43816d1a8389c860c1d162be44d1e777cfb4e1ffb05a3fb8f30002087075234ac47353b42bb97ce46330cb67cd4648c01f0b2393d7e729b0d6789182087075234ac47353b42bb97ce46330cb67cd4648c01f0b2393d7e729b0d678918000e33352e3136372e3134352e313439149b9cdbfe3568cc0b37f136b00a634c75653f05e3fb4e1ffb05a3fb8f30002088251bd4b124efeb87537deabeec54f6c8f575f4df81f10cf5e8eea073092b6f2088251bd4b124efeb87537deabeec54f6c8f575f4df81f10cf5e8eea073092b6f000b35322e33332e32382e343714711fd9548ae19b2e91c7a9b4067000467ccdd2b5fb4e1ffb05a3fb8f3000208917bb546318f3410d1a7901c7b846a73446311b5164b45a03f0e613f208f234208917bb546318f3410d1a7901c7b846a73446311b5164b45a03f0e613f208f234000d35322e31332e3133322e313436145bdbf34a0dad860c6ec71523ae39373325225cc1fb4e1ffb05a3fb8f3000208b8d1193afd22e538ce0c9fb50fee155d0f6176ca68e65da684c5dce2d1e0815208b8d1193afd22e538ce0c9fb50fee155d0f6176ca68e65da684c5dce2d1e0815000c35322e33342e3134342e353014a0a0e17bfe82a484fefe348b7569a6d77d29d2c2fb4e1ffb05a3fb8f3000208de8b12952f7058d827bd04cdff1c2175d87bbf89f28b52452a637bc979addc4208de8b12952f7058d827bd04cdff1c2175d87bbf89f28b52452a637bc979addc4000c35322e34332e38362e32333114337b7fb5d2c531825c3e0123ac3354018085b302fb4e1ffb05a3fb8f3000208e11eb784883d3dc9d0d74a74633f067dc61c408dfdee49b8f93bb161f2916c0208e11eb784883d3dc9d0d74a74633f067dc61c408dfdee49b8f93bb161f2916c0000c35322e38392e3135342e3438146d57707c196e06487d326094c964f258f5b77c35fb4e1ffb05a3fb8f3000209712e85d660fa2f761f980ef5812c225f33f336f285728803dcd421937d3df54209712e85d660fa2f761f980ef5812c225f33f336f285728803dcd421937d3df54000d33352e38322e3139372e31393714ed1131823bcea23ac78af8c01e4d24683d6ecf88fb4e1ffb05a3fb8f30002098ef58c338a0a68e4f2f1d1ee9eb05fcafbb9177d192dac0f698d3d9ba0920962098ef58c338a0a68e4f2f1d1ee9eb05fcafbb9177d192dac0f698d3d9ba092096000c34342e3233322e3139362e3614d6ece912cbf02627a4efc3dd37e6833cf3671551fb4e1ffb05a3fb8f300020b3b5748571b60fe9ad112715d6a51725d6e5a52a9c3af5fd36a1724cf50d862f20b3b5748571b60fe9ad112715d6a51725d6e5a52a9c3af5fd36a1724cf50d862f000b35322e34332e31332e39321441b308f737ca9e39f67b553158903198a88c516efb4e1ffb05a3fb8f300020bbfd0ac1977011267a7032641ef5487fe15a4de798faa485b156fb3b7eb0acb820bbfd0ac1977011267a7032641ef5487fe15a4de798faa485b156fb3b7eb0acb8000c33352e38322e34392e31393614dbbebbc52a5bae21b818e0487311041c91b2683bfb4e1ffb05a3fb8f300020c11c1168dcf9479475cb1355855e30ea75c0cdda8a8f9ea80591568dd1c33ba820c11c1168dcf9479475cb1355855e30ea75c0cdda8a8f9ea80591568dd1c33ba8000d35342e3231332e3230342e383514fdae7cdf38811659ce9481975b326a5d07236bc5fb4e1ffb05a3fb8f300020f6496d3c0ac1ad94ff5e3aab2edcabc1c8ba3fbfea0ef3026e90ba786399038120f6496d3c0ac1ad94ff5e3aab2edcabc1c8ba3fbfea0ef3026e90ba7863990381000d35322e31332e3235302e31383214fe2d4798df3e9b41a6823bc0b3f020478e87925dfb4e1ffb05a3fb8f300020ff261d2c1c76907a2ad8aeb6c5611796f03b5cbd88ae92452a4727e13f4f4ac920ff261d2c1c76907a2ad8aeb6c5611796f03b5cbd88ae92452a4727e13f4f4ac9000d35342e3138372e31342e3233321467e05b1b52c7c896adf20035036fe1d30dcefc9cfb4e1ffb05a3fb8f3000308363bb90232bac7a56c8a751b0e92029974d09eb0d894ddfa56e2cead1d7204e820692844e3ddbe248f477633e0c903b20000000e5d8948d2c695de557f1327a8f323fe00ea463ab53d415589456cae5430020000000e5d8948d2c695de557f1327a8f323fe00ea463ab53d415589456cae54300fc00110a48192005b687978344fa2433b2aa99d41f643e2d8581a789cdc23084889ceca5244ea82005b687978344fa2433b2aa99d41f643e2d8581a789cdc23084889ceca5244ea80130969e860529b2ff3468eb673067a839e89cb70cd1d945192b91965bd36d5d3fa4fe504619892c15f98225e79a3a7d47090d35322e32342e3132342e313632148feb00404d6f765856c95e587b2523a365bc7258fb4e1ffb05a3fb8f300020143dcd6a6b7684fde01e88a10e5d65de9a29244c5ecd586d14a342657025f11320143dcd6a6b7684fde01e88a10e5d65de9a29244c5ecd586d14a342657025f113013084cd37a5e9a78f8b1dd5642869b38051aeb448e0fd7f1d3848e33d649fc4631d4d49ff0931a050d59790bd0531f397200d33352e3136342e32332e32343514b5f25f8f70cf8d05c2d2970bdf186c994431d84efb4e1ffb05a3fb8f3000202e48651a2e9c0cb4f2fb7ab874061aa4af0cd28b59695631e6a35af3950ef6fb202e48651a2e9c0cb4f2fb7ab874061aa4af0cd28b59695631e6a35af3950ef6fb01308deb2b0dff4093f71fbafc7bae4b29b17ea30485ece48b32470952f9126356b873514122831c2951e7a3abb6f9a81bbe0d35342e3134392e33332e313637141ffbf1d32541dcb8f5555305295704a9ff9adc24fb4e1ffb05a3fb8f3000203971dab9691efac06e4ce7a5483131373e84726458924fe48b7d541791693be1203971dab9691efac06e4ce7a5483131373e84726458924fe48b7d541791693be10130a5f030ce39676a17427193f0ca4cc9ee43a4f902e107773cfa1e540b26cad7f267e8c3079b8cdf4c0add74a2e84dcea30d39322e36332e3137362e3230321461c274080f47a95be5372ef8c69bb60ab1d4ca82fb4e1ffb05a3fb8f30002039741ad83dd791e1e738f19edae82d6c0322972e6a455981424da3769b3dbd4a2039741ad83dd791e1e738f19edae82d6c0322972e6a455981424da3769b3dbd4a01308ebbe8af7fc4642314003a46929b4099c64842f64f9e69e6da327632aba34d40b35aea294ee5cb61d3d9acdaae8cd38b0e33352e3136332e3134342e32333014ec7bf3b9bc72eda38c80bb7cf16e294e763e56b4fb4e1ffb05a3fb8f3000205b246080ba64350685fe302d3d790f5bb238cb619920d46230c844f079944a23205b246080ba64350685fe302d3d790f5bb238cb619920d46230c844f079944a230130a63effa991db7f60139f66d7ce6d9b009b50415bea8a473e308d23b984e95c16e65dd19080c9dd203f0ff7a73a5946540d33352e3136352e35302e31323614f460a07a2b0dc932e1d8ff2dee2b984ac415dcebfb4e1ffb05a3fb8f3000207135069642e1a72807a383fb5a14b9af6758292fee53fe2a7f7ac6f528bf7019207135069642e1a72807a383fb5a14b9af6758292fee53fe2a7f7ac6f528bf701901308227fa4a5a3770831ee93c7f52edb284567beaf78c37ae47c6731589cafe50efd98478cb2b078310199b36b08a8c3e670d35342e3138392e3136342e333914f9956e70daffa263e8cf29fa6557b7b630a595a8fb4e1ffb05a3fb8f300020754b89dae8db20fc4cee5e3adb07b146d7efe508a66fa0a8e1094675b9daa35e20754b89dae8db20fc4cee5e3adb07b146d7efe508a66fa0a8e1094675b9daa35e0130aefc5fd6504acb6801a3531e8ca8c42a57c9891f61a505114dec9f0607aaa15ac5f1ab94f5b46c3bff9b12a31ee82b7b0c34342e3233332e34342e39351446d938862af6d9a291e26c0048177db2892a710bfb4e1ffb05a3fb8f3000207718edad371e46d20fad30086e4acf4a05c2b660df6ae5f2a684aebdf1be4290207718edad371e46d20fad30086e4acf4a05c2b660df6ae5f2a684aebdf1be4290013085d05de36a1b5ed656048a64569cf42a5807ce65c29a91c2b3a00f8bf9bdabe99715d3d62b8aab75b7173fcb36862abd0d34342e3232372e3133372e3737140498ade3c80045c2a7520e921180ae1c39da5c57fb4e1ffb05a3fb8f30002085f15a31d3838293a9c1d72a1a0fa21e66110ce20878bd4c1024c4ae1d5be8242085f15a31d3838293a9c1d72a1a0fa21e66110ce20878bd4c1024c4ae1d5be8240130a7c71dc1a14889412cd99e7c2714560d81fc63ec74ce9e6aff290503d28e4283fa41c09f7f33a0fa039cfdfeac4e71d70d35342e3230312e33322e3133311468c506d43816d1a8389c860c1d162be44d1e777cfb4e1ffb05a3fb8f30002087075234ac47353b42bb97ce46330cb67cd4648c01f0b2393d7e729b0d6789182087075234ac47353b42bb97ce46330cb67cd4648c01f0b2393d7e729b0d6789180130a858472dffbc0aabf6e25b30037d38a71a563359fce61c7f8636e15c16ed7373fef2ce7e476761c6c8f5c8d945fd976b0e33352e3136372e3134352e313439149b9cdbfe3568cc0b37f136b00a634c75653f05e3fb4e1ffb05a3fb8f30002088251bd4b124efeb87537deabeec54f6c8f575f4df81f10cf5e8eea073092b6f2088251bd4b124efeb87537deabeec54f6c8f575f4df81f10cf5e8eea073092b6f01308b0b6b19ffd7b384cc664de9d04e0bc65d75374df2ae888489812b122294904372b8df973d58795578e2f960692b46650b35322e33332e32382e343714711fd9548ae19b2e91c7a9b4067000467ccdd2b5fb4e1ffb05a3fb8f3000208917bb546318f3410d1a7901c7b846a73446311b5164b45a03f0e613f208f234208917bb546318f3410d1a7901c7b846a73446311b5164b45a03f0e613f208f2340130844d1bba28048dd41472b1c2b663cc37dbbe7633ce65d6d514a99b13234760ed0df5644596438d4ac52570742bcb564d0d35322e31332e3133322e313436145bdbf34a0dad860c6ec71523ae39373325225cc1fb4e1ffb05a3fb8f3000208b8d1193afd22e538ce0c9fb50fee155d0f6176ca68e65da684c5dce2d1e0815208b8d1193afd22e538ce0c9fb50fee155d0f6176ca68e65da684c5dce2d1e08150130a04e60f14500bec7d0a9dd2800de360694d7557767791090c96a271e854f74ec3cb9b6f77bf73a8ac6a8385b14f684850c35322e33342e3134342e353014a0a0e17bfe82a484fefe348b7569a6d77d29d2c2fb4e1ffb05a3fb8f3000208de8b12952f7058d827bd04cdff1c2175d87bbf89f28b52452a637bc979addc4208de8b12952f7058d827bd04cdff1c2175d87bbf89f28b52452a637bc979addc40130b122c5d8c54ed1f6697988003e6cf37ab70b25bd700e3c5217d85f56af1454b9e03a3ebf8882af455650e1ec1cf6e02f0c35322e34332e38362e32333114337b7fb5d2c531825c3e0123ac3354018085b302fb4e1ffb05a3fb8f3000208e11eb784883d3dc9d0d74a74633f067dc61c408dfdee49b8f93bb161f2916c0208e11eb784883d3dc9d0d74a74633f067dc61c408dfdee49b8f93bb161f2916c00130b5a22609f0513b65e2157a13109628f1b5a58802347518e7b16edc63d7f555e9218c437b67cef2f5c2e0852fa39f2ead0c35322e38392e3135342e3438146d57707c196e06487d326094c964f258f5b77c35fb4e1ffb05a3fb8f3000208eca4bcbb3a124ab283afd42dad3bdb2077b3809659788a0f1daffce5b9f001f208eca4bcbb3a124ab283afd42dad3bdb2077b3809659788a0f1daffce5b9f001f0130b52c68fe953aa91acadea41238e533cf63e0fe775d9bfad8cf300d746517e9141e1e09ed9470f50f599fc3726108a3a80d35342e36382e3233352e32303114c075993a8336f93a13bb7bbb7e0e89928be4aafbfb4e1ffb05a3fb8f30002091bbce94c34ebde0d099c0a2cb7635c0c31425ebabcec644f4f1a0854bfa605d2091bbce94c34ebde0d099c0a2cb7635c0c31425ebabcec644f4f1a0854bfa605d013090d6d5f5e92a3cf42953447fc2993da64507785ab28e8d800f24a203759ec184ecb4581bf4bc797265d159db56ad21130c35322e34302e3231392e34311402aa69f8ef6666e7cad6d9323755a0ef3c1b6bd9fb4e1ffb05a3fb8f30002098ef58c338a0a68e4f2f1d1ee9eb05fcafbb9177d192dac0f698d3d9ba0920962098ef58c338a0a68e4f2f1d1ee9eb05fcafbb9177d192dac0f698d3d9ba09209601308ce455a85113cbb3f226996c42cffe8ec3c18879e7f3351844b36bd6f455d092f26e1593c67847077b794e9b9338df500c34342e3233322e3139362e3614d6ece912cbf02627a4efc3dd37e6833cf3671551fb4e1ffb05a3fb8f3000209cb04f271ba050132c00cc5838fb69e77bc55b5689f9d2d850dc528935f8145c209cb04f271ba050132c00cc5838fb69e77bc55b5689f9d2d850dc528935f8145c01308bde4bc57ed1376b3c1ea5cbfa427aa4e7f5458d3bb7bbcdd3edf5ff1316d636082ecf6adf8d91a6b1f294743e09e0e40c33342e3231342e34382e36381462e960a3f6b650feed98a266b3ccdf6e363562cffb4e1ffb05a3fb8f300020ba8ce1dc72857b4168e33272571df7fbaf84c316dfe48217addcf6595e25421620ba8ce1dc72857b4168e33272571df7fbaf84c316dfe48217addcf6595e2542160130b5c487a28336e7e237dc06a260855ccadac81c0befca82d851f59a62dd037dbf4245a9c8d3851993c39b831a4ae41e800d35322e34322e3230322e3132381462e0104ce0aafc1f06bde37c73702fe84b307f05fb4e1ffb05a3fb8f300020bbfd0ac1977011267a7032641ef5487fe15a4de798faa485b156fb3b7eb0acb820bbfd0ac1977011267a7032641ef5487fe15a4de798faa485b156fb3b7eb0acb80130b1538d4316211a05c7e88931ab8c9ac68bf59f3a157be38c7c59db2e0edd27ab4acf632546aaaf74da4c3c52da02c3a90c33352e38322e34392e31393614dbbebbc52a5bae21b818e0487311041c91b2683bfb4e1ffb05a3fb8f300020c11c1168dcf9479475cb1355855e30ea75c0cdda8a8f9ea80591568dd1c33ba820c11c1168dcf9479475cb1355855e30ea75c0cdda8a8f9ea80591568dd1c33ba80130a042172d66535219d6616449610f3257ea2a1661ab700ad8e242f56e708fdd4328005f7a256e90c48b58660d73c895e20d35342e3231332e3230342e383514fdae7cdf38811659ce9481975b326a5d07236bc5fb4e1ffb05a3fb8f300020f6496d3c0ac1ad94ff5e3aab2edcabc1c8ba3fbfea0ef3026e90ba786399038120f6496d3c0ac1ad94ff5e3aab2edcabc1c8ba3fbfea0ef3026e90ba78639903810130b1897a9037794f448cb3d65fcfe458a68af52b1193075b21f5c54ceb480b50aacafc12c705ecbeab07655a5db52344920d35322e31332e3235302e31383214fe2d4798df3e9b41a6823bc0b3f020478e87925dfb4e1ffb05a3fb8f300020ff261d2c1c76907a2ad8aeb6c5611796f03b5cbd88ae92452a4727e13f4f4ac920ff261d2c1c76907a2ad8aeb6c5611796f03b5cbd88ae92452a4727e13f4f4ac90130ac6b9425d33076bd863a8331058733b29ec6da69d70936e7af23576e747971d7e1f54ecbcbe92e70cc9a4ea725d9bffa0d35342e3138372e31342e3233321467e05b1b52c7c896adf20035036fe1d30dcefc9cfb4e1ffb05a3fb8f300030b9b745e239b0131f2ae8386bf2512c0548e499cbcb27d722b29982c464f3f4854dffd934fc633ca893a8b20b76b4b5cd200000000b8cd4ead1ee12d25126921d918020cd77745d9cce5b59f7287a2a296e00200000000b8cd4ead1ee12d25126921d918020cd77745d9cce5b59f7287a2a296e00fc00110a301920143dcd6a6b7684fde01e88a10e5d65de9a29244c5ecd586d14a342657025f11320143dcd6a6b7684fde01e88a10e5d65de9a29244c5ecd586d14a342657025f1130130804fb84c41e4ef70fa136be9e1b4a1de7509d51d4f4f48ad0be8b6689cfb888b3376611201c88f8d2ff4b8bbc8859ab10d33352e3136342e32332e32343514b5f25f8f70cf8d05c2d2970bdf186c994431d84efb4e1ffb05a3fb8f30002020107ec50e81880dca18178bb7e53e2d0449c0734106a607253b9af2ffea006c2020107ec50e81880dca18178bb7e53e2d0449c0734106a607253b9af2ffea006c0130966937f030398b1e57153a449a48f5a8cc4b17782b4553075050498ed6acae479e1b8f053ba7fea2dcdb8511b01cc8330c33352e38352e32312e3137391435d9eb76397d05b43b5cd8da7ccfa8408bc89ab3fb4e1ffb05a3fb8f3000202e48651a2e9c0cb4f2fb7ab874061aa4af0cd28b59695631e6a35af3950ef6fb202e48651a2e9c0cb4f2fb7ab874061aa4af0cd28b59695631e6a35af3950ef6fb0130a0e490268a9ac6f614abda6d2c9773f78027df23205e51319d26e4a59e6226dbd2d44dadf21a7fc2af9bfa4491436e0e0d35342e3134392e33332e313637141ffbf1d32541dcb8f5555305295704a9ff9adc24fb4e1ffb05a3fb8f30002039741ad83dd791e1e738f19edae82d6c0322972e6a455981424da3769b3dbd4a2039741ad83dd791e1e738f19edae82d6c0322972e6a455981424da3769b3dbd4a013088e19fb0f79180331d93d2e1a9bd84a2b35505cc72aefef50d427196df3025478cf19f15478dc4f8e36379a2c762946d0e33352e3136332e3134342e32333014ec7bf3b9bc72eda38c80bb7cf16e294e763e56b4fb4e1ffb05a3fb8f3000205b246080ba64350685fe302d3d790f5bb238cb619920d46230c844f079944a23205b246080ba64350685fe302d3d790f5bb238cb619920d46230c844f079944a230130995b7089c977df3b5855d481b20dddfc3a203a0b28c0d899929948e3c634138d0d6e4166b95a62bf2aeb7bfb77b33b430d33352e3136352e35302e31323614f460a07a2b0dc932e1d8ff2dee2b984ac415dcebfb4e1ffb05a3fb8f3000205c6542766615387183715d958a925552472f93335fa1612880423e4bbdaef436205c6542766615387183715d958a925552472f93335fa1612880423e4bbdaef4360130a8cddde49c1a90c2977def8b0cb06bf1f1545163c01accb8d5b489c6a57b86da38fe13ad211315efb16065d049edb6d90d34342e3233392e33392e31353314972a33056d57359de8acfa4fb8b29dc1c14f76b8fb4e1ffb05a3fb8f30002061d33f478933797be4de88353c7c2d843c21310f6d00f6eff31424a756ee7dfb2061d33f478933797be4de88353c7c2d843c21310f6d00f6eff31424a756ee7dfb0130a979e9907653676d99ad236d9d7ad7f1caa7b8c145a631e86e9a3c7f217bf1af6c96f591860661775bd0703bad1be8c50c35322e31322e3137362e3930147ada3e486409b39c94a0833c8d782f35bc24e96afb4e1ffb05a3fb8f3000206d1b185ba036efcd44a77e05a9aaf69a0c4e40976aec00b04773e52863320966206d1b185ba036efcd44a77e05a9aaf69a0c4e40976aec00b04773e528633209660130b2af25880010cc44b694bfd03af48b1d67d1c8f7799aba3803537d66bad445b5a9ade42f1a169d82e29ec29d5b509e670e34342e3232382e3234322e31383114c374f016ea61e76aab79b8bb95a1ba0e6e3eee6ffb4e1ffb05a3fb8f3000207135069642e1a72807a383fb5a14b9af6758292fee53fe2a7f7ac6f528bf7019207135069642e1a72807a383fb5a14b9af6758292fee53fe2a7f7ac6f528bf7019013097d6313c96e3d4a72866547f8b6946b0b16027404c3941645533649fab02ce8c68c1b1fe153ebfc450ac4f0c197de8220d35342e3138392e3136342e333914f9956e70daffa263e8cf29fa6557b7b630a595a8fb4e1ffb05a3fb8f300020754b89dae8db20fc4cee5e3adb07b146d7efe508a66fa0a8e1094675b9daa35e20754b89dae8db20fc4cee5e3adb07b146d7efe508a66fa0a8e1094675b9daa35e0130985bda42120b76d3118d53f76ff49f8f1056a6d9044c165498acd2449afcf0f04928090aacce43f95bb1130f1774c2a10c34342e3233332e34342e39351446d938862af6d9a291e26c0048177db2892a710bfb4e1ffb05a3fb8f3000207718edad371e46d20fad30086e4acf4a05c2b660df6ae5f2a684aebdf1be4290207718edad371e46d20fad30086e4acf4a05c2b660df6ae5f2a684aebdf1be429001308c99f0600654d103f2cc2e8afd413f92ce0b1703e4b2695e441ea6ca41c04aa02b17a417f537c3738fc2d55c9d7c465c0d34342e3232372e3133372e3737140498ade3c80045c2a7520e921180ae1c39da5c57fb4e1ffb05a3fb8f30002085f15a31d3838293a9c1d72a1a0fa21e66110ce20878bd4c1024c4ae1d5be8242085f15a31d3838293a9c1d72a1a0fa21e66110ce20878bd4c1024c4ae1d5be8240130b3ebfc2a01c5e5f81e5b751db91cbbb2dd28a8125221d91c7cabe348abea7140ba157311cb0706e8b2a021ca4b9df7980d35342e3230312e33322e3133311468c506d43816d1a8389c860c1d162be44d1e777cfb4e1ffb05a3fb8f30002088251bd4b124efeb87537deabeec54f6c8f575f4df81f10cf5e8eea073092b6f2088251bd4b124efeb87537deabeec54f6c8f575f4df81f10cf5e8eea073092b6f0130a9a7425ddeee5373c8dc48863d1c7a9abd856a95d26f4146dd818c0b8d8e7669d4a35837b83e1fc1c32ed951dcd179350b35322e33332e32382e343714711fd9548ae19b2e91c7a9b4067000467ccdd2b5fb4e1ffb05a3fb8f3000208917bb546318f3410d1a7901c7b846a73446311b5164b45a03f0e613f208f234208917bb546318f3410d1a7901c7b846a73446311b5164b45a03f0e613f208f2340130b98ebc6724479085f5da42cb91861d1449a3ca648d955751f5c3b91b096a840f092676c348f2f00b5039481dca12b9630d35322e31332e3133322e313436145bdbf34a0dad860c6ec71523ae39373325225cc1fb4e1ffb05a3fb8f3000208b8d1193afd22e538ce0c9fb50fee155d0f6176ca68e65da684c5dce2d1e0815208b8d1193afd22e538ce0c9fb50fee155d0f6176ca68e65da684c5dce2d1e08150130a61f28db421160121dfc7c0fb707c0a28d7ee8bbf0f3ae522029783af248144b8ff12015083e6cc7f7dcf42c0f7455710c35322e33342e3134342e353014a0a0e17bfe82a484fefe348b7569a6d77d29d2c2fb4e1ffb05a3fb8f3000208de8b12952f7058d827bd04cdff1c2175d87bbf89f28b52452a637bc979addc4208de8b12952f7058d827bd04cdff1c2175d87bbf89f28b52452a637bc979addc40130b2cad9ab34e5a8d11dc038e34918476731a014a4d250e087c0231690acce6eb1dc5aee354356f83eb0171f5269c9b8820c35322e34332e38362e32333114337b7fb5d2c531825c3e0123ac3354018085b302fb4e1ffb05a3fb8f3000208e11eb784883d3dc9d0d74a74633f067dc61c408dfdee49b8f93bb161f2916c0208e11eb784883d3dc9d0d74a74633f067dc61c408dfdee49b8f93bb161f2916c0013083bdc72d5ba2383a5fcd5b3f69df233b38363c98a191de6ab39375b6a88b529a150a314d448714ea7908433c9bf2cfd90c35322e38392e3135342e3438146d57707c196e06487d326094c964f258f5b77c35fb4e1ffb05a3fb8f3000209712e85d660fa2f761f980ef5812c225f33f336f285728803dcd421937d3df54209712e85d660fa2f761f980ef5812c225f33f336f285728803dcd421937d3df540130a13129fdef659fc1d53aeebb283e3dfaf398ded529cd03046faa4452c09f0dd3b9507c128a8fff1379f41f6dc3f3dca40d33352e38322e3139372e31393714ed1131823bcea23ac78af8c01e4d24683d6ecf88fb4e1ffb05a3fb8f30002098ef58c338a0a68e4f2f1d1ee9eb05fcafbb9177d192dac0f698d3d9ba0920962098ef58c338a0a68e4f2f1d1ee9eb05fcafbb9177d192dac0f698d3d9ba0920960130a02732ceeb00cbc22c6a3513e33364fbbe668f9b18d6d179a0ae8a624e54d6e70313ee5d114f4a90934c558046d7778b0c34342e3233322e3139362e3614d6ece912cbf02627a4efc3dd37e6833cf3671551fb4e1ffb05a3fb8f3000209cb04f271ba050132c00cc5838fb69e77bc55b5689f9d2d850dc528935f8145c209cb04f271ba050132c00cc5838fb69e77bc55b5689f9d2d850dc528935f8145c0130b8b9bde8dd4ada170f591c79c7799b3a3110da70e66a5d9bd958c0ee09aa9318b66a51b6e848f9d89ebdc95aa03f98890c33342e3231342e34382e36381462e960a3f6b650feed98a266b3ccdf6e363562cffb4e1ffb05a3fb8f300020b3b5748571b60fe9ad112715d6a51725d6e5a52a9c3af5fd36a1724cf50d862f20b3b5748571b60fe9ad112715d6a51725d6e5a52a9c3af5fd36a1724cf50d862f0130b066eb4def83361ffc67185aa1e0d731674c29b63f6094195e51fcd538ea20d92dd4a8d565fa5a4952d7003a6dc6ae860b35322e34332e31332e39321441b308f737ca9e39f67b553158903198a88c516efb4e1ffb05a3fb8f300020ba8ce1dc72857b4168e33272571df7fbaf84c316dfe48217addcf6595e25421620ba8ce1dc72857b4168e33272571df7fbaf84c316dfe48217addcf6595e2542160130a6e8c59c8ca50f24d6ba38e9c2170eb7e7ecb218025bf5b872e7757127dff5e358f8996cedeffb73183d75e0da1ce2a80d35322e34322e3230322e3132381462e0104ce0aafc1f06bde37c73702fe84b307f05fb4e1ffb05a3fb8f300020bbfd0ac1977011267a7032641ef5487fe15a4de798faa485b156fb3b7eb0acb820bbfd0ac1977011267a7032641ef5487fe15a4de798faa485b156fb3b7eb0acb80130b02657330749afaba1d7f537a8d7a2f7f5d769dfeb35c611997de1fde5aeee25a2b36cd5b29658a99bfa26ac11295ef10c33352e38322e34392e31393614dbbebbc52a5bae21b818e0487311041c91b2683bfb4e1ffb05a3fb8f300020c11c1168dcf9479475cb1355855e30ea75c0cdda8a8f9ea80591568dd1c33ba820c11c1168dcf9479475cb1355855e30ea75c0cdda8a8f9ea80591568dd1c33ba8013096b913b9291edf58bd3dcaa9d4ca9a22cbcfdb8aa5ca6e3f0be4b9c84f251ab1a4dedc2eb735aab46559e71d81d34d580d35342e3231332e3230342e383514fdae7cdf38811659ce9481975b326a5d07236bc5fb4e1ffb05a3fb8f300020d9b090cfc19caf2e27d512e69c43812a274bdf29c081d0ade4fd272ad56a5f8920d9b090cfc19caf2e27d512e69c43812a274bdf29c081d0ade4fd272ad56a5f89013085fc1d0b5171e799df05263801d116cb5091e8b61a6dedaeb7d555acc70faebf8888c32892877db163f92fb3d37697510d34342e3234302e39382e313032147034f0d3853c5351fb8e0ffd3c1daf12c51c2d89fb4e1ffb05a3fb8f30003098dbb9b35974480142186275c072950c403c009244f48be412f76d3fdbbb079126b9a3e2d9902d74fb3fcf571179c8ba200000013b5860da205d4132c60deedcd2f06f18c77718fc9f96a5473d05e596fa00200000013b5860da205d4132c60deedcd2f06f18c77718fc9f96a5473d05e596fa00fc00110a18192005b687978344fa2433b2aa99d41f643e2d8581a789cdc23084889ceca5244ea82005b687978344fa2433b2aa99d41f643e2d8581a789cdc23084889ceca5244ea80130aefbe4d19c74f3038be0d800cecadf43701500341a07b66c54780eff1d919af02df5981f40298d42d71a21203f5861830d35322e32342e3132342e313632148feb00404d6f765856c95e587b2523a365bc7258fb4e1ffb05a3fb8f30002020107ec50e81880dca18178bb7e53e2d0449c0734106a607253b9af2ffea006c2020107ec50e81880dca18178bb7e53e2d0449c0734106a607253b9af2ffea006c0130a6318708e3cf020d9a4d6acc99290e20852673b3fd56111a41f768d62c774cf7634621e292811aadacba01405ee0dd4c0c33352e38352e32312e3137391435d9eb76397d05b43b5cd8da7ccfa8408bc89ab3fb4e1ffb05a3fb8f3000203971dab9691efac06e4ce7a5483131373e84726458924fe48b7d541791693be1203971dab9691efac06e4ce7a5483131373e84726458924fe48b7d541791693be10130932daaeb7b3d00c345c7928cf668dd5b93f00c8ae932c3b02ec60a32f3bc70a06d54de27ebcd7d754ba8ab457d4220fe0d39322e36332e3137362e3230321461c274080f47a95be5372ef8c69bb60ab1d4ca82fb4e1ffb05a3fb8f30002039741ad83dd791e1e738f19edae82d6c0322972e6a455981424da3769b3dbd4a2039741ad83dd791e1e738f19edae82d6c0322972e6a455981424da3769b3dbd4a0130b6dc1e01c3c5adf1c45d2ffdc8b3e2bb191ddc96155093c44d2ea4dbf825a1b58c2a9b2f352ea9bfb82069224dfc12a20e33352e3136332e3134342e32333014ec7bf3b9bc72eda38c80bb7cf16e294e763e56b4fb4e1ffb05a3fb8f30002040784f3f9a761c60156f9244a902c0626f8bc8fe003786c70f1fc6be41da467d2040784f3f9a761c60156f9244a902c0626f8bc8fe003786c70f1fc6be41da467d0130aacc0b07512ca510f795d08610bb19b86765fab3ebe38247bc66894bb487873517751be72d6623aa4c6f0de8b9fb86300c35322e31302e3232392e3131143e8b10646ee9d6c28d75c280b357dd3a9ae9f962fb4e1ffb05a3fb8f3000205b246080ba64350685fe302d3d790f5bb238cb619920d46230c844f079944a23205b246080ba64350685fe302d3d790f5bb238cb619920d46230c844f079944a230130b2386d3b8287a94917087b2214107fb7604a296aaa68ad405c267cfe0ac50254edc13916213526c93ae969da3e2e19dd0d33352e3136352e35302e31323614f460a07a2b0dc932e1d8ff2dee2b984ac415dcebfb4e1ffb05a3fb8f3000205c6542766615387183715d958a925552472f93335fa1612880423e4bbdaef436205c6542766615387183715d958a925552472f93335fa1612880423e4bbdaef436013089a560690e28c68c6503d32257037db0901e0e7e58e2a49502f27ef146faf9785c3a6d0d7a83f51f54e8a416b8fc5d5a0d34342e3233392e33392e31353314972a33056d57359de8acfa4fb8b29dc1c14f76b8fb4e1ffb05a3fb8f30002061d33f478933797be4de88353c7c2d843c21310f6d00f6eff31424a756ee7dfb2061d33f478933797be4de88353c7c2d843c21310f6d00f6eff31424a756ee7dfb01308123b9c30ea0afee794b67b78633b351d4e8a6861f9089db1eddaea2063052b4b8e6fe6d7aa8adaa8d14daee571921190c35322e31322e3137362e3930147ada3e486409b39c94a0833c8d782f35bc24e96afb4e1ffb05a3fb8f3000206d1b185ba036efcd44a77e05a9aaf69a0c4e40976aec00b04773e52863320966206d1b185ba036efcd44a77e05a9aaf69a0c4e40976aec00b04773e5286332096601308784b66c8bacc5e407ba4388af1ce9634c0c65fae5ccb415d99622e2568fddd81860551836c6857651b7e68bf777051e0e34342e3232382e3234322e31383114c374f016ea61e76aab79b8bb95a1ba0e6e3eee6ffb4e1ffb05a3fb8f3000207135069642e1a72807a383fb5a14b9af6758292fee53fe2a7f7ac6f528bf7019207135069642e1a72807a383fb5a14b9af6758292fee53fe2a7f7ac6f528bf7019013088ca8aaf57cc7e2af48b2036bc3ce08b729115792ddd891d748809feb5131a78834a444d4bf5d682372030bdef0aeef60d35342e3138392e3136342e333914f9956e70daffa263e8cf29fa6557b7b630a595a8fb4e1ffb05a3fb8f3000207718edad371e46d20fad30086e4acf4a05c2b660df6ae5f2a684aebdf1be4290207718edad371e46d20fad30086e4acf4a05c2b660df6ae5f2a684aebdf1be429001308a1844847acbbd40ed0102cf8978803b46626cf1ff053d3962dc017bcf9274ac64016269ed9c4cbaaea230cd582ce7c10d34342e3232372e3133372e3737140498ade3c80045c2a7520e921180ae1c39da5c57fb4e1ffb05a3fb8f30002087075234ac47353b42bb97ce46330cb67cd4648c01f0b2393d7e729b0d6789182087075234ac47353b42bb97ce46330cb67cd4648c01f0b2393d7e729b0d6789180130b2bb87347b1d029ee08969d8b183be7cb5bb7030333e7b1ebc590ef95bbdea0060106943d82fe1287e66b0a6ea9fbda70e33352e3136372e3134352e313439149b9cdbfe3568cc0b37f136b00a634c75653f05e3fb4e1ffb05a3fb8f30002088251bd4b124efeb87537deabeec54f6c8f575f4df81f10cf5e8eea073092b6f2088251bd4b124efeb87537deabeec54f6c8f575f4df81f10cf5e8eea073092b6f0130902b68a0d6aaaa88f5448e7847aa844ca290312883ccc45d513b6f55c186a66b430d9be46a39b36d65968f35e21672c50b35322e33332e32382e343714711fd9548ae19b2e91c7a9b4067000467ccdd2b5fb4e1ffb05a3fb8f3000208917bb546318f3410d1a7901c7b846a73446311b5164b45a03f0e613f208f234208917bb546318f3410d1a7901c7b846a73446311b5164b45a03f0e613f208f2340130b02ec92b3976b32d0fe09a82c478f9ad352a176b4af5c95c14021a39068e8e0f0ee3a9665a7347dadcc5495a6c54be830d35322e31332e3133322e313436145bdbf34a0dad860c6ec71523ae39373325225cc1fb4e1ffb05a3fb8f3000208de8b12952f7058d827bd04cdff1c2175d87bbf89f28b52452a637bc979addc4208de8b12952f7058d827bd04cdff1c2175d87bbf89f28b52452a637bc979addc40130a8b4baf7a0ad0776ad239d4795d86e25d77a4f59d054ed7c4dcc31f97ded0485e6a0b1475d744f20b491438d2e53937f0c35322e34332e38362e32333114337b7fb5d2c531825c3e0123ac3354018085b302fb4e1ffb05a3fb8f3000208e11eb784883d3dc9d0d74a74633f067dc61c408dfdee49b8f93bb161f2916c0208e11eb784883d3dc9d0d74a74633f067dc61c408dfdee49b8f93bb161f2916c00130a220d7da059c4f6129c623b728dd3f59f9e12f4d6cb81a7291ed72323f48906c411cf04b926906323e4fcf9c64a7afa20c35322e38392e3135342e3438146d57707c196e06487d326094c964f258f5b77c35fb4e1ffb05a3fb8f30002091bbce94c34ebde0d099c0a2cb7635c0c31425ebabcec644f4f1a0854bfa605d2091bbce94c34ebde0d099c0a2cb7635c0c31425ebabcec644f4f1a0854bfa605d013090dc1560bf0fee4e480e85565e796ba90608bcdc82c5be50a17a0276126b3011c0b05c53d5b57971677ee6dc4065e2620c35322e34302e3231392e34311402aa69f8ef6666e7cad6d9323755a0ef3c1b6bd9fb4e1ffb05a3fb8f3000209712e85d660fa2f761f980ef5812c225f33f336f285728803dcd421937d3df54209712e85d660fa2f761f980ef5812c225f33f336f285728803dcd421937d3df540130a280d0efc97a9f5877d4d5d26842c2b1eb5a972f6721ad04f59379ceeee8eea2279b41c55b2d91f326d1a081e2308b2c0d33352e38322e3139372e31393714ed1131823bcea23ac78af8c01e4d24683d6ecf88fb4e1ffb05a3fb8f30002098ef58c338a0a68e4f2f1d1ee9eb05fcafbb9177d192dac0f698d3d9ba0920962098ef58c338a0a68e4f2f1d1ee9eb05fcafbb9177d192dac0f698d3d9ba0920960130ae50333bb9c084b8235209009bc79e95ac93ea7e720f645f40210985cacb95d938359f1c2054c54f8ffecc46b46c72520c34342e3233322e3139362e3614d6ece912cbf02627a4efc3dd37e6833cf3671551fb4e1ffb05a3fb8f3000209cb04f271ba050132c00cc5838fb69e77bc55b5689f9d2d850dc528935f8145c209cb04f271ba050132c00cc5838fb69e77bc55b5689f9d2d850dc528935f8145c0130902df93b14e13fa8c2bc56f8dd885933e7664a040742e9db1944c022a362f1f59bf392c8f2b619b6aa902751a0d97eb60c33342e3231342e34382e36381462e960a3f6b650feed98a266b3ccdf6e363562cffb4e1ffb05a3fb8f300020b3b5748571b60fe9ad112715d6a51725d6e5a52a9c3af5fd36a1724cf50d862f20b3b5748571b60fe9ad112715d6a51725d6e5a52a9c3af5fd36a1724cf50d862f0130b846359de05b4e141f1bf41c6f11a74858fead3a20c0b197f25eb081056520000a8e5f665d2504b0c3722d07fe9d48390b35322e34332e31332e39321441b308f737ca9e39f67b553158903198a88c516efb4e1ffb05a3fb8f300020bbfd0ac1977011267a7032641ef5487fe15a4de798faa485b156fb3b7eb0acb820bbfd0ac1977011267a7032641ef5487fe15a4de798faa485b156fb3b7eb0acb80130b64ffd3afa423be6e3c703eba0a16b25c86ec60e391d005bf47a73d33c66bcf7d0b2172d0f55041ee8d7869f7c6f352c0c33352e38322e34392e31393614dbbebbc52a5bae21b818e0487311041c91b2683bfb4e1ffb05a3fb8f300020d9b090cfc19caf2e27d512e69c43812a274bdf29c081d0ade4fd272ad56a5f8920d9b090cfc19caf2e27d512e69c43812a274bdf29c081d0ade4fd272ad56a5f890130a6314c087034d4edfdb09dee1471a52b7906905da4510346d1a4c932c40174a753d2658cdbc734b83430d9a19fde876b0d34342e3234302e39382e313032147034f0d3853c5351fb8e0ffd3c1daf12c51c2d89fb4e1ffb05a3fb8f300020f6496d3c0ac1ad94ff5e3aab2edcabc1c8ba3fbfea0ef3026e90ba786399038120f6496d3c0ac1ad94ff5e3aab2edcabc1c8ba3fbfea0ef3026e90ba78639903810130a3c22f17c427c3f66373ab1eada7d9288fcb81114eaed49edd48647aada20c6d439f2d603cc9f4d00e92cbe844f432910d35322e31332e3235302e31383214fe2d4798df3e9b41a6823bc0b3f020478e87925dfb4e1ffb05a3fb8f300020ff261d2c1c76907a2ad8aeb6c5611796f03b5cbd88ae92452a4727e13f4f4ac920ff261d2c1c76907a2ad8aeb6c5611796f03b5cbd88ae92452a4727e13f4f4ac90130b5ea66b9c53fbbe4159192277264bfec6873a97e5c585a7adf5a62cbae4481aceface1dff0868ea001ed514810a75fe60d35342e3138372e31342e3233321467e05b1b52c7c896adf20035036fe1d30dcefc9cfb4e1ffb05a3fb8f30003082d71ec73b651ee1603038edce0b1b453e6cdf03a7c5dae542ecfa36e8e646ad5f8b2c6fd2947ebf3504a1e9aa36a3112000000050b5530a426cc3a37ae64b7e37879c0905cd90391226fd7395a19cad2b002000000050b5530a426cc3a37ae64b7e37879c0905cd90391226fd7395a19cad2b00fc00110a00192005b687978344fa2433b2aa99d41f643e2d8581a789cdc23084889ceca5244ea82005b687978344fa2433b2aa99d41f643e2d8581a789cdc23084889ceca5244ea8000d35322e32342e3132342e313632148feb00404d6f765856c95e587b2523a365bc7258fb4e1ffb05a3fb8f30002012de3ea6678dadb1db529b7fa98762160625055de2aa34e757c93c136233f4a22012de3ea6678dadb1db529b7fa98762160625055de2aa34e757c93c136233f4a2000e3231322e32342e3130332e31343914c1161c96de3dae28cd7f20ff8c2aa7b94b866d76fb4e1ffb05a3fb8f300020143dcd6a6b7684fde01e88a10e5d65de9a29244c5ecd586d14a342657025f11320143dcd6a6b7684fde01e88a10e5d65de9a29244c5ecd586d14a342657025f113000d33352e3136342e32332e32343514b5f25f8f70cf8d05c2d2970bdf186c994431d84efb4e1ffb05a3fb8f30002020107ec50e81880dca18178bb7e53e2d0449c0734106a607253b9af2ffea006c2020107ec50e81880dca18178bb7e53e2d0449c0734106a607253b9af2ffea006c000c33352e38352e32312e3137391435d9eb76397d05b43b5cd8da7ccfa8408bc89ab3fb4e1ffb05a3fb8f3000202e48651a2e9c0cb4f2fb7ab874061aa4af0cd28b59695631e6a35af3950ef6fb202e48651a2e9c0cb4f2fb7ab874061aa4af0cd28b59695631e6a35af3950ef6fb000d35342e3134392e33332e313637141ffbf1d32541dcb8f5555305295704a9ff9adc24fb4e1ffb05a3fb8f30002040784f3f9a761c60156f9244a902c0626f8bc8fe003786c70f1fc6be41da467d2040784f3f9a761c60156f9244a902c0626f8bc8fe003786c70f1fc6be41da467d000c35322e31302e3232392e3131143e8b10646ee9d6c28d75c280b357dd3a9ae9f962fb4e1ffb05a3fb8f3000205c6542766615387183715d958a925552472f93335fa1612880423e4bbdaef436205c6542766615387183715d958a925552472f93335fa1612880423e4bbdaef436000d34342e3233392e33392e31353314972a33056d57359de8acfa4fb8b29dc1c14f76b8fb4e1ffb05a3fb8f30002061d33f478933797be4de88353c7c2d843c21310f6d00f6eff31424a756ee7dfb2061d33f478933797be4de88353c7c2d843c21310f6d00f6eff31424a756ee7dfb000c35322e31322e3137362e3930147ada3e486409b39c94a0833c8d782f35bc24e96afb4e1ffb05a3fb8f3000206d1b185ba036efcd44a77e05a9aaf69a0c4e40976aec00b04773e52863320966206d1b185ba036efcd44a77e05a9aaf69a0c4e40976aec00b04773e52863320966000e34342e3232382e3234322e31383114c374f016ea61e76aab79b8bb95a1ba0e6e3eee6ffb4e1ffb05a3fb8f300020754b89dae8db20fc4cee5e3adb07b146d7efe508a66fa0a8e1094675b9daa35e20754b89dae8db20fc4cee5e3adb07b146d7efe508a66fa0a8e1094675b9daa35e000c34342e3233332e34342e39351446d938862af6d9a291e26c0048177db2892a710bfb4e1ffb05a3fb8f3000207718edad371e46d20fad30086e4acf4a05c2b660df6ae5f2a684aebdf1be4290207718edad371e46d20fad30086e4acf4a05c2b660df6ae5f2a684aebdf1be4290000d34342e3232372e3133372e3737140498ade3c80045c2a7520e921180ae1c39da5c57fb4e1ffb05a3fb8f30002085f15a31d3838293a9c1d72a1a0fa21e66110ce20878bd4c1024c4ae1d5be8242085f15a31d3838293a9c1d72a1a0fa21e66110ce20878bd4c1024c4ae1d5be824000d35342e3230312e33322e3133311468c506d43816d1a8389c860c1d162be44d1e777cfb4e1ffb05a3fb8f30002087075234ac47353b42bb97ce46330cb67cd4648c01f0b2393d7e729b0d6789182087075234ac47353b42bb97ce46330cb67cd4648c01f0b2393d7e729b0d678918000e33352e3136372e3134352e313439149b9cdbfe3568cc0b37f136b00a634c75653f05e3fb4e1ffb05a3fb8f30002088251bd4b124efeb87537deabeec54f6c8f575f4df81f10cf5e8eea073092b6f2088251bd4b124efeb87537deabeec54f6c8f575f4df81f10cf5e8eea073092b6f000b35322e33332e32382e343714711fd9548ae19b2e91c7a9b4067000467ccdd2b5fb4e1ffb05a3fb8f3000208917bb546318f3410d1a7901c7b846a73446311b5164b45a03f0e613f208f234208917bb546318f3410d1a7901c7b846a73446311b5164b45a03f0e613f208f234000d35322e31332e3133322e313436145bdbf34a0dad860c6ec71523ae39373325225cc1fb4e1ffb05a3fb8f3000208b8d1193afd22e538ce0c9fb50fee155d0f6176ca68e65da684c5dce2d1e0815208b8d1193afd22e538ce0c9fb50fee155d0f6176ca68e65da684c5dce2d1e0815000c35322e33342e3134342e353014a0a0e17bfe82a484fefe348b7569a6d77d29d2c2fb4e1ffb05a3fb8f3000208de8b12952f7058d827bd04cdff1c2175d87bbf89f28b52452a637bc979addc4208de8b12952f7058d827bd04cdff1c2175d87bbf89f28b52452a637bc979addc4000c35322e34332e38362e32333114337b7fb5d2c531825c3e0123ac3354018085b302fb4e1ffb05a3fb8f3000208eca4bcbb3a124ab283afd42dad3bdb2077b3809659788a0f1daffce5b9f001f208eca4bcbb3a124ab283afd42dad3bdb2077b3809659788a0f1daffce5b9f001f000d35342e36382e3233352e32303114c075993a8336f93a13bb7bbb7e0e89928be4aafbfb4e1ffb05a3fb8f3000209712e85d660fa2f761f980ef5812c225f33f336f285728803dcd421937d3df54209712e85d660fa2f761f980ef5812c225f33f336f285728803dcd421937d3df54000d33352e38322e3139372e31393714ed1131823bcea23ac78af8c01e4d24683d6ecf88fb4e1ffb05a3fb8f30002098ef58c338a0a68e4f2f1d1ee9eb05fcafbb9177d192dac0f698d3d9ba0920962098ef58c338a0a68e4f2f1d1ee9eb05fcafbb9177d192dac0f698d3d9ba092096000c34342e3233322e3139362e3614d6ece912cbf02627a4efc3dd37e6833cf3671551fb4e1ffb05a3fb8f3000209cb04f271ba050132c00cc5838fb69e77bc55b5689f9d2d850dc528935f8145c209cb04f271ba050132c00cc5838fb69e77bc55b5689f9d2d850dc528935f8145c000c33342e3231342e34382e36381462e960a3f6b650feed98a266b3ccdf6e363562cffb4e1ffb05a3fb8f300020bbfd0ac1977011267a7032641ef5487fe15a4de798faa485b156fb3b7eb0acb820bbfd0ac1977011267a7032641ef5487fe15a4de798faa485b156fb3b7eb0acb8000c33352e38322e34392e31393614dbbebbc52a5bae21b818e0487311041c91b2683bfb4e1ffb05a3fb8f300020c11c1168dcf9479475cb1355855e30ea75c0cdda8a8f9ea80591568dd1c33ba820c11c1168dcf9479475cb1355855e30ea75c0cdda8a8f9ea80591568dd1c33ba8000d35342e3231332e3230342e383514fdae7cdf38811659ce9481975b326a5d07236bc5fb4e1ffb05a3fb8f300020d9b090cfc19caf2e27d512e69c43812a274bdf29c081d0ade4fd272ad56a5f8920d9b090cfc19caf2e27d512e69c43812a274bdf29c081d0ade4fd272ad56a5f89000d34342e3234302e39382e313032147034f0d3853c5351fb8e0ffd3c1daf12c51c2d89fb4e1ffb05a3fb8f300020f6496d3c0ac1ad94ff5e3aab2edcabc1c8ba3fbfea0ef3026e90ba786399038120f6496d3c0ac1ad94ff5e3aab2edcabc1c8ba3fbfea0ef3026e90ba7863990381000d35322e31332e3235302e31383214fe2d4798df3e9b41a6823bc0b3f020478e87925dfb4e1ffb05a3fb8f3000309115ebe490480078d6ed0b6cbb6b14a67e8c87a481a9b899ad9b69df05b58319a845f03c8b12333714e40cd371e867842000000029787a10cbbd05260d3c7a8114746b568d0a5fbd2fdb9f080ac12c5acd002000000029787a10cbbd05260d3c7a8114746b568d0a5fbd2fdb9f080ac12c5acd00fc001109e8192005b687978344fa2433b2aa99d41f643e2d8581a789cdc23084889ceca5244ea82005b687978344fa2433b2aa99d41f643e2d8581a789cdc23084889ceca5244ea80130970d7b81b480412fc43ea1f788843b1d09f0dc907586b3e260b050c7644f6d41fb27b1a42c480e34004c32c09977e93f0d35322e32342e3132342e313632148feb00404d6f765856c95e587b2523a365bc7258fb4e1ffb05a3fb8f30002012de3ea6678dadb1db529b7fa98762160625055de2aa34e757c93c136233f4a22012de3ea6678dadb1db529b7fa98762160625055de2aa34e757c93c136233f4a20130a820e13b8769adac09e564cd1cb18bc063cfcf3924f15636b0760c4f5b0fe84cf2fb570335b9f5a480e175a1d3bf271c0e3231322e32342e3130332e31343914c1161c96de3dae28cd7f20ff8c2aa7b94b866d76fb4e1ffb05a3fb8f300020143dcd6a6b7684fde01e88a10e5d65de9a29244c5ecd586d14a342657025f11320143dcd6a6b7684fde01e88a10e5d65de9a29244c5ecd586d14a342657025f113013098a0e5d3895c330ff366206535e6868f2b68d9a187883d14a20d439471981e61b208ab0e8a3550b3a9b896864e2e97630d33352e3136342e32332e32343514b5f25f8f70cf8d05c2d2970bdf186c994431d84efb4e1ffb05a3fb8f30002020107ec50e81880dca18178bb7e53e2d0449c0734106a607253b9af2ffea006c2020107ec50e81880dca18178bb7e53e2d0449c0734106a607253b9af2ffea006c0130a5873d03f1d4625d480393ef389ef41c6c64d996285ffa796cc08208824d35dccf69f861d6adc1692fb714c09031a02b0c33352e38352e32312e3137391435d9eb76397d05b43b5cd8da7ccfa8408bc89ab3fb4e1ffb05a3fb8f3000202e48651a2e9c0cb4f2fb7ab874061aa4af0cd28b59695631e6a35af3950ef6fb202e48651a2e9c0cb4f2fb7ab874061aa4af0cd28b59695631e6a35af3950ef6fb0130b202608dae582e081fddaf3e2a6a79cb3f843fb9af4edcc5c5ca173c3802851be056b863ca2e7f754d6ebd7273dce89c0d35342e3134392e33332e313637141ffbf1d32541dcb8f5555305295704a9ff9adc24fb4e1ffb05a3fb8f3000203971dab9691efac06e4ce7a5483131373e84726458924fe48b7d541791693be1203971dab9691efac06e4ce7a5483131373e84726458924fe48b7d541791693be101308292b344b60fc7e2a7039a8d36fad7680caa319305f1a48bf517c70d669145757311e299990b96f2a1725d8d15122c210d39322e36332e3137362e3230321461c274080f47a95be5372ef8c69bb60ab1d4ca82fb4e1ffb05a3fb8f30002040784f3f9a761c60156f9244a902c0626f8bc8fe003786c70f1fc6be41da467d2040784f3f9a761c60156f9244a902c0626f8bc8fe003786c70f1fc6be41da467d01308022bb20ab0892ac7fceddccffafed851a6b99462fe1fbc8ed302eb13dcd34104e8b640d6863e22b3c0334c65bb1353d0c35322e31302e3232392e3131143e8b10646ee9d6c28d75c280b357dd3a9ae9f962fb4e1ffb05a3fb8f3000205b246080ba64350685fe302d3d790f5bb238cb619920d46230c844f079944a23205b246080ba64350685fe302d3d790f5bb238cb619920d46230c844f079944a230130a8d80210f5a8421b7d0e7aefb73de90996043824f763ba7ba2f2bccf65fe2692a843be92a6c948e3ec379cc4873ab8620d33352e3136352e35302e31323614f460a07a2b0dc932e1d8ff2dee2b984ac415dcebfb4e1ffb05a3fb8f3000205c6542766615387183715d958a925552472f93335fa1612880423e4bbdaef436205c6542766615387183715d958a925552472f93335fa1612880423e4bbdaef43601308b71e75c86b6dbe16c8d77b58c54c3046b879c9b2870ad5978bd66822a5495c088be770cbaa7b07606e4bea48f1d57520d34342e3233392e33392e31353314972a33056d57359de8acfa4fb8b29dc1c14f76b8fb4e1ffb05a3fb8f3000207135069642e1a72807a383fb5a14b9af6758292fee53fe2a7f7ac6f528bf7019207135069642e1a72807a383fb5a14b9af6758292fee53fe2a7f7ac6f528bf70190130a5db974fcc27c6e6659be41f6e60cda5595e476219e92f1a42891a2129efa57e7168cb1ed7e910567b28b50f49ec89580d35342e3138392e3136342e333914f9956e70daffa263e8cf29fa6557b7b630a595a8fb4e1ffb05a3fb8f300020754b89dae8db20fc4cee5e3adb07b146d7efe508a66fa0a8e1094675b9daa35e20754b89dae8db20fc4cee5e3adb07b146d7efe508a66fa0a8e1094675b9daa35e01308a0faa9aa37cb733914dcb2f0238e7ecd1cc6e1bca84ea82f40f56ac676cfbfdddfebb17145fd119724acbac6526925d0c34342e3233332e34342e39351446d938862af6d9a291e26c0048177db2892a710bfb4e1ffb05a3fb8f3000207718edad371e46d20fad30086e4acf4a05c2b660df6ae5f2a684aebdf1be4290207718edad371e46d20fad30086e4acf4a05c2b660df6ae5f2a684aebdf1be42900130a43cce1d88a28cce331807a9d82ebb836e179712045ecb44f4d9e30e3dadd1fd56eb794e1ff4b77f6389cf070ab4335e0d34342e3232372e3133372e3737140498ade3c80045c2a7520e921180ae1c39da5c57fb4e1ffb05a3fb8f30002085f15a31d3838293a9c1d72a1a0fa21e66110ce20878bd4c1024c4ae1d5be8242085f15a31d3838293a9c1d72a1a0fa21e66110ce20878bd4c1024c4ae1d5be8240130ac38307fb06ab201fad2e7d995746ca822aa65b3efacdb2944840dc49cae820ef8cda959b3022fa5825aa6c185b2d2e80d35342e3230312e33322e3133311468c506d43816d1a8389c860c1d162be44d1e777cfb4e1ffb05a3fb8f30002088251bd4b124efeb87537deabeec54f6c8f575f4df81f10cf5e8eea073092b6f2088251bd4b124efeb87537deabeec54f6c8f575f4df81f10cf5e8eea073092b6f0130b0a830cc01b28f5268aae63f37e8edee59c0cf638e56add0f8fc6a63fa67754d550acb8c1844fe49dd969384b3e47d4d0b35322e33332e32382e343714711fd9548ae19b2e91c7a9b4067000467ccdd2b5fb4e1ffb05a3fb8f3000208917bb546318f3410d1a7901c7b846a73446311b5164b45a03f0e613f208f234208917bb546318f3410d1a7901c7b846a73446311b5164b45a03f0e613f208f2340130897c23a6f47c9459e7c374ab0fa826f27a035794b8aeb965fd6ee02bac15546e4c74b4dc878f9aeca6811ee30376479a0d35322e31332e3133322e313436145bdbf34a0dad860c6ec71523ae39373325225cc1fb4e1ffb05a3fb8f3000208b8d1193afd22e538ce0c9fb50fee155d0f6176ca68e65da684c5dce2d1e0815208b8d1193afd22e538ce0c9fb50fee155d0f6176ca68e65da684c5dce2d1e08150130923d83d963dcad047de4b636c1002972099365c6ca34d86b2b0c4d9d5f1e3c76a82a4775b6973933f08b4efca67c39140c35322e33342e3134342e353014a0a0e17bfe82a484fefe348b7569a6d77d29d2c2fb4e1ffb05a3fb8f3000208de8b12952f7058d827bd04cdff1c2175d87bbf89f28b52452a637bc979addc4208de8b12952f7058d827bd04cdff1c2175d87bbf89f28b52452a637bc979addc40130acf9fca5575dd9432d04bf48208d4d6233327efd892d7dc8a19c221875b19150e386e59c596a26f805c51b782266ed2d0c35322e34332e38362e32333114337b7fb5d2c531825c3e0123ac3354018085b302fb4e1ffb05a3fb8f3000208e11eb784883d3dc9d0d74a74633f067dc61c408dfdee49b8f93bb161f2916c0208e11eb784883d3dc9d0d74a74633f067dc61c408dfdee49b8f93bb161f2916c001309656eb5ec24456fafd42a36eaaa7777a1a07126cdba616f306f5922962edb86c84eb63eb1c4fe73b77c2c125c03e0e8a0c35322e38392e3135342e3438146d57707c196e06487d326094c964f258f5b77c35fb4e1ffb05a3fb8f3000208eca4bcbb3a124ab283afd42dad3bdb2077b3809659788a0f1daffce5b9f001f208eca4bcbb3a124ab283afd42dad3bdb2077b3809659788a0f1daffce5b9f001f01308458cd94f39953a2cbe980f26296dbc935f5bfa0c51840267d34529a14c40a62dbbcde39372748c0c555169d692852dd0d35342e36382e3233352e32303114c075993a8336f93a13bb7bbb7e0e89928be4aafbfb4e1ffb05a3fb8f3000209712e85d660fa2f761f980ef5812c225f33f336f285728803dcd421937d3df54209712e85d660fa2f761f980ef5812c225f33f336f285728803dcd421937d3df540130b8986d8ccb4735db954e68d32a0d544778f631523e347b673ec19f522241a4a78e842d21e3dbafaf7c1dde9b7a87af610d33352e38322e3139372e31393714ed1131823bcea23ac78af8c01e4d24683d6ecf88fb4e1ffb05a3fb8f3000209cb04f271ba050132c00cc5838fb69e77bc55b5689f9d2d850dc528935f8145c209cb04f271ba050132c00cc5838fb69e77bc55b5689f9d2d850dc528935f8145c0130a4922f49f620b1db38fa2ee28facca3aa818e29858e47d8afa467f1f6e78512f7f81b09ec5debc0d6ba820c5afcf730a0c33342e3231342e34382e36381462e960a3f6b650feed98a266b3ccdf6e363562cffb4e1ffb05a3fb8f300020b3b5748571b60fe9ad112715d6a51725d6e5a52a9c3af5fd36a1724cf50d862f20b3b5748571b60fe9ad112715d6a51725d6e5a52a9c3af5fd36a1724cf50d862f0130b0bd0eaedab09436d694b6fbfd5d7ff130d10a5b0793363383556d4d4e203892d50c6d7ff5fd418c113e46dd03e680f90b35322e34332e31332e39321441b308f737ca9e39f67b553158903198a88c516efb4e1ffb05a3fb8f300020ba8ce1dc72857b4168e33272571df7fbaf84c316dfe48217addcf6595e25421620ba8ce1dc72857b4168e33272571df7fbaf84c316dfe48217addcf6595e254216013096b15178f4a27b4e2c957fba6321c9e0c6a52cc181b78bdff133af13378578429140857bcd7bef984123d4a0c1bb0a0f0d35322e34322e3230322e3132381462e0104ce0aafc1f06bde37c73702fe84b307f05fb4e1ffb05a3fb8f300020d9b090cfc19caf2e27d512e69c43812a274bdf29c081d0ade4fd272ad56a5f8920d9b090cfc19caf2e27d512e69c43812a274bdf29c081d0ade4fd272ad56a5f890130a92fbcf877ae8f1126dd2000c14f94e984b0b8417ef08a5d41e8e4f25b1c4345d604ea4d5628cb3b465c0f133c1680ea0d34342e3234302e39382e313032147034f0d3853c5351fb8e0ffd3c1daf12c51c2d89fb4e1ffb05a3fb8f300020f6496d3c0ac1ad94ff5e3aab2edcabc1c8ba3fbfea0ef3026e90ba786399038120f6496d3c0ac1ad94ff5e3aab2edcabc1c8ba3fbfea0ef3026e90ba7863990381013080cf4159f981ea771039b37a355c87b1b63d08f5ca1fe187b43dab3d69aba34c296486fbe95169d4e86aff8e5b7d4ec10d35322e31332e3235302e31383214fe2d4798df3e9b41a6823bc0b3f020478e87925dfb4e1ffb05a3fb8f300030b9cbddb5cb09af2419de553627792b168d70fec7f4b86455fad63931bd68cef1eb7aee5d8b52e592167c2b5e2b7778b420000000ca47540e3e2bbbfc91ad3581df6b5f730ea457841a3544e2ab3c54c2450020000000ca47540e3e2bbbfc91ad3581df6b5f730ea457841a3544e2ab3c54c24500fc001109d0192005b687978344fa2433b2aa99d41f643e2d8581a789cdc23084889ceca5244ea82005b687978344fa2433b2aa99d41f643e2d8581a789cdc23084889ceca5244ea80130b8b06499c583a0fd22b6891f1b2fbc982c65889f34a41303a4e6add3335e6f03de51013907906849ae0606f4642546e90d35322e32342e3132342e313632148feb00404d6f765856c95e587b2523a365bc7258fb4e1ffb05a3fb8f30002012de3ea6678dadb1db529b7fa98762160625055de2aa34e757c93c136233f4a22012de3ea6678dadb1db529b7fa98762160625055de2aa34e757c93c136233f4a20130a74f5ce985df2786c2aff01e9030ac94d60a087d9bb7e67f6ed82fd2bfdec5ffa365fa0234cc36cffe48ed7a891566f40e3231322e32342e3130332e31343914c1161c96de3dae28cd7f20ff8c2aa7b94b866d76fb4e1ffb05a3fb8f300020143dcd6a6b7684fde01e88a10e5d65de9a29244c5ecd586d14a342657025f11320143dcd6a6b7684fde01e88a10e5d65de9a29244c5ecd586d14a342657025f113013089c4a5d69af324ffe22e0c8d9b8b0dd4ebcc23a8947dbefa423dd21d6bca38d83903018bd19233fdf82db3cf58b121120d33352e3136342e32332e32343514b5f25f8f70cf8d05c2d2970bdf186c994431d84efb4e1ffb05a3fb8f30002020107ec50e81880dca18178bb7e53e2d0449c0734106a607253b9af2ffea006c2020107ec50e81880dca18178bb7e53e2d0449c0734106a607253b9af2ffea006c0130a97a7c20f8e962e0f42eb82a8574a40d592a6c045e2d0dd022d30ae7580f63121f1b127de8c8fdbc0a09be310be140630c33352e38352e32312e3137391435d9eb76397d05b43b5cd8da7ccfa8408bc89ab3fb4e1ffb05a3fb8f3000202e48651a2e9c0cb4f2fb7ab874061aa4af0cd28b59695631e6a35af3950ef6fb202e48651a2e9c0cb4f2fb7ab874061aa4af0cd28b59695631e6a35af3950ef6fb013095b29cd5c1260dad12e00db7df6264adf1e129db92db275c512024ef882d525bc76aae7b91e98cc50f02b467b729a4230d35342e3134392e33332e313637141ffbf1d32541dcb8f5555305295704a9ff9adc24fb4e1ffb05a3fb8f3000203971dab9691efac06e4ce7a5483131373e84726458924fe48b7d541791693be1203971dab9691efac06e4ce7a5483131373e84726458924fe48b7d541791693be10130b36395d295eb39ab7a37a6dbae201d69783252554528616a2cd694ece2bcfa1c228bfbe9f11189e58464f1f818222cb80d39322e36332e3137362e3230321461c274080f47a95be5372ef8c69bb60ab1d4ca82fb4e1ffb05a3fb8f30002039741ad83dd791e1e738f19edae82d6c0322972e6a455981424da3769b3dbd4a2039741ad83dd791e1e738f19edae82d6c0322972e6a455981424da3769b3dbd4a0130a5c5eb179bcfa04fff58a455c31a4434d2956ee64992ad90fa984e22bb0271349b34ed391adb5d14e92fe4e909e66fed0e33352e3136332e3134342e32333014ec7bf3b9bc72eda38c80bb7cf16e294e763e56b4fb4e1ffb05a3fb8f30002040784f3f9a761c60156f9244a902c0626f8bc8fe003786c70f1fc6be41da467d2040784f3f9a761c60156f9244a902c0626f8bc8fe003786c70f1fc6be41da467d0130990581eeaa1de281b5b427562103f13d36926683d2fd547c9594ef7814b4eae5d1873a8935db2014270fbf6a8324a0650c35322e31302e3232392e3131143e8b10646ee9d6c28d75c280b357dd3a9ae9f962fb4e1ffb05a3fb8f3000205b246080ba64350685fe302d3d790f5bb238cb619920d46230c844f079944a23205b246080ba64350685fe302d3d790f5bb238cb619920d46230c844f079944a23013092859d855e078b0d51bb59700c2f97084b7b9cb756877df99999a141599e2398a1d801ba447e87243666bfccda43b3a80d33352e3136352e35302e31323614f460a07a2b0dc932e1d8ff2dee2b984ac415dcebfb4e1ffb05a3fb8f3000205c6542766615387183715d958a925552472f93335fa1612880423e4bbdaef436205c6542766615387183715d958a925552472f93335fa1612880423e4bbdaef4360130a517a483d86831f719bea10f0fd570a991d4d31f842eacdb7bcedd2b4574832c8c9f8faffdf3dd5855b958fab30f28ea0d34342e3233392e33392e31353314972a33056d57359de8acfa4fb8b29dc1c14f76b8fb4e1ffb05a3fb8f30002061d33f478933797be4de88353c7c2d843c21310f6d00f6eff31424a756ee7dfb2061d33f478933797be4de88353c7c2d843c21310f6d00f6eff31424a756ee7dfb01308d6b47b552e835caf543b4e12228069e2b017e9697e9a53769477a17f911ebb6d60902335c80dbc5f8a3f1fddb901a2d0c35322e31322e3137362e3930147ada3e486409b39c94a0833c8d782f35bc24e96afb4e1ffb05a3fb8f30002085f15a31d3838293a9c1d72a1a0fa21e66110ce20878bd4c1024c4ae1d5be8242085f15a31d3838293a9c1d72a1a0fa21e66110ce20878bd4c1024c4ae1d5be8240130959e4b96408015ba5f09b91b6075879d793c8e23ac87c8c7bfb488570359603a5555912d439396eff96196a8a48509350d35342e3230312e33322e3133311468c506d43816d1a8389c860c1d162be44d1e777cfb4e1ffb05a3fb8f30002087075234ac47353b42bb97ce46330cb67cd4648c01f0b2393d7e729b0d6789182087075234ac47353b42bb97ce46330cb67cd4648c01f0b2393d7e729b0d6789180130b48413f0072f49e797ac6d1e24416a891a045f9381882ee222801da1872c6edc1f96b10d5fc1e35ac986dabbe1a6bebb0e33352e3136372e3134352e313439149b9cdbfe3568cc0b37f136b00a634c75653f05e3fb4e1ffb05a3fb8f30002088251bd4b124efeb87537deabeec54f6c8f575f4df81f10cf5e8eea073092b6f2088251bd4b124efeb87537deabeec54f6c8f575f4df81f10cf5e8eea073092b6f013080b9a527a7102ef8fa92958d687466a5e660408c19aa20631b5ba92e6ad6c05ce0756df6fb5ddef9f3541096b1a507c60b35322e33332e32382e343714711fd9548ae19b2e91c7a9b4067000467ccdd2b5fb4e1ffb05a3fb8f3000208917bb546318f3410d1a7901c7b846a73446311b5164b45a03f0e613f208f234208917bb546318f3410d1a7901c7b846a73446311b5164b45a03f0e613f208f234013096224eff9b71fa242635fc530e66dc5a352d930491a7f6835420101c3f5f9ded42b8b81342d46430e7cc2a7d2c6118640d35322e31332e3133322e313436145bdbf34a0dad860c6ec71523ae39373325225cc1fb4e1ffb05a3fb8f3000208e11eb784883d3dc9d0d74a74633f067dc61c408dfdee49b8f93bb161f2916c0208e11eb784883d3dc9d0d74a74633f067dc61c408dfdee49b8f93bb161f2916c001308b083dafad8abb0439badd1bee47c8c40ff94d9b0cb3a170e80b79d7291eff897897984cb854f731777298d9a4c53ff70c35322e38392e3135342e3438146d57707c196e06487d326094c964f258f5b77c35fb4e1ffb05a3fb8f3000208eca4bcbb3a124ab283afd42dad3bdb2077b3809659788a0f1daffce5b9f001f208eca4bcbb3a124ab283afd42dad3bdb2077b3809659788a0f1daffce5b9f001f013099ec50553765cb873f210513dc1f50cf370711af9283042cfa0047b50de960c54343213a10f86443605e72c8158fbdbe0d35342e36382e3233352e32303114c075993a8336f93a13bb7bbb7e0e89928be4aafbfb4e1ffb05a3fb8f30002091bbce94c34ebde0d099c0a2cb7635c0c31425ebabcec644f4f1a0854bfa605d2091bbce94c34ebde0d099c0a2cb7635c0c31425ebabcec644f4f1a0854bfa605d01309418730d55f9813b944c857e73544681bfb28cfb0cb8f80cc6853b060ce980d5124c451302681fd64507973dafd4fe050c35322e34302e3231392e34311402aa69f8ef6666e7cad6d9323755a0ef3c1b6bd9fb4e1ffb05a3fb8f3000209712e85d660fa2f761f980ef5812c225f33f336f285728803dcd421937d3df54209712e85d660fa2f761f980ef5812c225f33f336f285728803dcd421937d3df5401309373b16af5c5922151307961ff6ba2932577a762412ddcecd8ea5e9d9de353687517a99179641a64867412dfa02b30e50d33352e38322e3139372e31393714ed1131823bcea23ac78af8c01e4d24683d6ecf88fb4e1ffb05a3fb8f30002098ef58c338a0a68e4f2f1d1ee9eb05fcafbb9177d192dac0f698d3d9ba0920962098ef58c338a0a68e4f2f1d1ee9eb05fcafbb9177d192dac0f698d3d9ba0920960130aa42f5cc6c6b0b157ebbccb51c179e6da1f657aa975cfe316bba65bb795d27c1a36fc89f277310e10d648b4eb2f3a4d70c34342e3233322e3139362e3614d6ece912cbf02627a4efc3dd37e6833cf3671551fb4e1ffb05a3fb8f300020b3b5748571b60fe9ad112715d6a51725d6e5a52a9c3af5fd36a1724cf50d862f20b3b5748571b60fe9ad112715d6a51725d6e5a52a9c3af5fd36a1724cf50d862f0130b9b68ea1d8c99b7cf1241fe98bbb671d4503b181af78d2cdd3b6c26717c5bbcc0f9977fd5e1ba2a89681f2c7193b30590b35322e34332e31332e39321441b308f737ca9e39f67b553158903198a88c516efb4e1ffb05a3fb8f300020bbfd0ac1977011267a7032641ef5487fe15a4de798faa485b156fb3b7eb0acb820bbfd0ac1977011267a7032641ef5487fe15a4de798faa485b156fb3b7eb0acb80130b9b9b9d80cac56a2354054847aad75cac16f3e004983c4287887ce67fe9151dc85ca64efced2acbb2fe1249edb97aeaa0c33352e38322e34392e31393614dbbebbc52a5bae21b818e0487311041c91b2683bfb4e1ffb05a3fb8f300020d9b090cfc19caf2e27d512e69c43812a274bdf29c081d0ade4fd272ad56a5f8920d9b090cfc19caf2e27d512e69c43812a274bdf29c081d0ade4fd272ad56a5f8901308c5fe2277f8f09c710ebc292b57abae1db9fb98a55db37c6d84d22d28616b0241a136a89addfbcf6d40a7cca5fbeb7020d34342e3234302e39382e313032147034f0d3853c5351fb8e0ffd3c1daf12c51c2d89fb4e1ffb05a3fb8f300020f6496d3c0ac1ad94ff5e3aab2edcabc1c8ba3fbfea0ef3026e90ba786399038120f6496d3c0ac1ad94ff5e3aab2edcabc1c8ba3fbfea0ef3026e90ba78639903810130b29a3615c31170fc5065b8c97c12db5f6dc30a6f7d3d851f7e8b5794dd4868b72eac1cf8e0938af1818f36eccf96b7560d35322e31332e3235302e31383214fe2d4798df3e9b41a6823bc0b3f020478e87925dfb4e1ffb05a3fb8f300020ff261d2c1c76907a2ad8aeb6c5611796f03b5cbd88ae92452a4727e13f4f4ac920ff261d2c1c76907a2ad8aeb6c5611796f03b5cbd88ae92452a4727e13f4f4ac90130a7219c2a26bf3628b8dad42325c9e2d03dd265015c2552990081ac3461f49b1ffc0e89f32fe01155655b12f2e5a2869f0d35342e3138372e31342e3233321467e05b1b52c7c896adf20035036fe1d30dcefc9cfb4e1ffb05a3fb8f300030b16ea424860dc0726c5e7215e1e982a42eab9330137b9fc25cb52f631237c875a75c2f1f601750686e417f0ccbdf398120000000e7654d577ec30cf6779bb7f025807118c9ee33113ea249fa1ce94906460020000000e7654d577ec30cf6779bb7f025807118c9ee33113ea249fa1ce949064600fc001109b8192005b687978344fa2433b2aa99d41f643e2d8581a789cdc23084889ceca5244ea82005b687978344fa2433b2aa99d41f643e2d8581a789cdc23084889ceca5244ea801308b962de6fb2b78ecd4a0d38a1e6599629e2f2ee7cf9bf120d2a42a5187f6b7bff3ad999d489ad01402952e13a7b2a0cd0d35322e32342e3132342e313632148feb00404d6f765856c95e587b2523a365bc7258fb4e1ffb05a3fb8f30002012de3ea6678dadb1db529b7fa98762160625055de2aa34e757c93c136233f4a22012de3ea6678dadb1db529b7fa98762160625055de2aa34e757c93c136233f4a201308f075ac06941ccf4426e74cca625cba70aa51383684e5b2ca68a5969980c577692a2a4fc04eaf6d75e06d46d47789d8a0e3231322e32342e3130332e31343914c1161c96de3dae28cd7f20ff8c2aa7b94b866d76fb4e1ffb05a3fb8f300020143dcd6a6b7684fde01e88a10e5d65de9a29244c5ecd586d14a342657025f11320143dcd6a6b7684fde01e88a10e5d65de9a29244c5ecd586d14a342657025f113013094ef996c8d9e5d050b0eb315c2953b3e7a6a2c0c814a4f091b0a899758193809d59932a177bb4bfe3612795c1cb1af180d33352e3136342e32332e32343514b5f25f8f70cf8d05c2d2970bdf186c994431d84efb4e1ffb05a3fb8f30002020107ec50e81880dca18178bb7e53e2d0449c0734106a607253b9af2ffea006c2020107ec50e81880dca18178bb7e53e2d0449c0734106a607253b9af2ffea006c0130b5c4608e61eec256009dced5e14f32abea62323bf9afc6bd3aa94775a69deffb4fbe7ced991719ae42f0464143739c050c33352e38352e32312e3137391435d9eb76397d05b43b5cd8da7ccfa8408bc89ab3fb4e1ffb05a3fb8f3000202e48651a2e9c0cb4f2fb7ab874061aa4af0cd28b59695631e6a35af3950ef6fb202e48651a2e9c0cb4f2fb7ab874061aa4af0cd28b59695631e6a35af3950ef6fb0130af4e360b85ba0e07ff4daf222828646b8553d34e13d27e0c0ab73b8d0819a7de542c8b75b908f2a522783805e98161ed0d35342e3134392e33332e313637141ffbf1d32541dcb8f5555305295704a9ff9adc24fb4e1ffb05a3fb8f3000203971dab9691efac06e4ce7a5483131373e84726458924fe48b7d541791693be1203971dab9691efac06e4ce7a5483131373e84726458924fe48b7d541791693be10130b3c583538cd672a8811fd6ad676f0ab86fb20142cde7318f6821ab80c747d667e65aac29cad1642220484b528e2b97a60d39322e36332e3137362e3230321461c274080f47a95be5372ef8c69bb60ab1d4ca82fb4e1ffb05a3fb8f30002039741ad83dd791e1e738f19edae82d6c0322972e6a455981424da3769b3dbd4a2039741ad83dd791e1e738f19edae82d6c0322972e6a455981424da3769b3dbd4a01308fa018aa37212ef01b6736ed5642f2e72bee1de375bfa8b8b670d3f91c6740d603d4d28712b4bf20a9823816dc0395220e33352e3136332e3134342e32333014ec7bf3b9bc72eda38c80bb7cf16e294e763e56b4fb4e1ffb05a3fb8f30002040784f3f9a761c60156f9244a902c0626f8bc8fe003786c70f1fc6be41da467d2040784f3f9a761c60156f9244a902c0626f8bc8fe003786c70f1fc6be41da467d0130864d618197d9c45ce9466461c76b2a7706c7651d52fd0a9c66dacea54359b82788580f51c44144d13d03924a2f231a6b0c35322e31302e3232392e3131143e8b10646ee9d6c28d75c280b357dd3a9ae9f962fb4e1ffb05a3fb8f3000205b246080ba64350685fe302d3d790f5bb238cb619920d46230c844f079944a23205b246080ba64350685fe302d3d790f5bb238cb619920d46230c844f079944a230130b7e90c414091b2b3fc3167cdf880027601fa23caacd4d806e561dd60368f4926fbf2794ed7256d2b9cae61cdd37cf61a0d33352e3136352e35302e31323614f460a07a2b0dc932e1d8ff2dee2b984ac415dcebfb4e1ffb05a3fb8f30002061d33f478933797be4de88353c7c2d843c21310f6d00f6eff31424a756ee7dfb2061d33f478933797be4de88353c7c2d843c21310f6d00f6eff31424a756ee7dfb01308062ad18e48955d3c60465639795e5eb5d06a307710278c033336338e1f165bb3f38d8193b331e7b8e5c7174f1bcc3290c35322e31322e3137362e3930147ada3e486409b39c94a0833c8d782f35bc24e96afb4e1ffb05a3fb8f3000206d1b185ba036efcd44a77e05a9aaf69a0c4e40976aec00b04773e52863320966206d1b185ba036efcd44a77e05a9aaf69a0c4e40976aec00b04773e528633209660130a3c4dc99f61b79db373f2cbb31282dab6c9f1e061d3ae149f292e7d2a57867af64dbaff63d8209eb2eae7bc4d19f18ba0e34342e3232382e3234322e31383114c374f016ea61e76aab79b8bb95a1ba0e6e3eee6ffb4e1ffb05a3fb8f3000207135069642e1a72807a383fb5a14b9af6758292fee53fe2a7f7ac6f528bf7019207135069642e1a72807a383fb5a14b9af6758292fee53fe2a7f7ac6f528bf70190130b0d3a176e29c34f594cd740859a21fdeddea237d66b706439b745b64da4bc910a6454a6c24766007bef5fddc60025aa00d35342e3138392e3136342e333914f9956e70daffa263e8cf29fa6557b7b630a595a8fb4e1ffb05a3fb8f300020754b89dae8db20fc4cee5e3adb07b146d7efe508a66fa0a8e1094675b9daa35e20754b89dae8db20fc4cee5e3adb07b146d7efe508a66fa0a8e1094675b9daa35e01308f9b3c93f75c54aaa7e94af920af8d570dbeccc8f03976a95aa6cd4956c57c4320ff54d3b9a6383801d78f3e89e842880c34342e3233332e34342e39351446d938862af6d9a291e26c0048177db2892a710bfb4e1ffb05a3fb8f30002087075234ac47353b42bb97ce46330cb67cd4648c01f0b2393d7e729b0d6789182087075234ac47353b42bb97ce46330cb67cd4648c01f0b2393d7e729b0d678918013098bacabb7caa139502f082638a2c5557402755a734420a4170e0625ba4cc6a90236624023c697478134010ecf2a024710e33352e3136372e3134352e313439149b9cdbfe3568cc0b37f136b00a634c75653f05e3fb4e1ffb05a3fb8f30002088251bd4b124efeb87537deabeec54f6c8f575f4df81f10cf5e8eea073092b6f2088251bd4b124efeb87537deabeec54f6c8f575f4df81f10cf5e8eea073092b6f01308f176c317a778eb340cbff32a482253eccade757f6be7ce3264efb3cc6bae9a49f44ac1634dbd916280d1f935f4da87c0b35322e33332e32382e343714711fd9548ae19b2e91c7a9b4067000467ccdd2b5fb4e1ffb05a3fb8f3000208b8d1193afd22e538ce0c9fb50fee155d0f6176ca68e65da684c5dce2d1e0815208b8d1193afd22e538ce0c9fb50fee155d0f6176ca68e65da684c5dce2d1e081501309861cc2ef8a3969143f1b32a715a6e10c3c2d7ba46cb7bc54e4e8101f08b85589f3ad825896c5b21e5d608d9200496840c35322e33342e3134342e353014a0a0e17bfe82a484fefe348b7569a6d77d29d2c2fb4e1ffb05a3fb8f3000208de8b12952f7058d827bd04cdff1c2175d87bbf89f28b52452a637bc979addc4208de8b12952f7058d827bd04cdff1c2175d87bbf89f28b52452a637bc979addc40130a45b1a6bffa54f659e58329868160e6e4503756ebffe1cc7bba724987832f81811883638133ef1b55a877a0650e6c4d10c35322e34332e38362e32333114337b7fb5d2c531825c3e0123ac3354018085b302fb4e1ffb05a3fb8f3000208e11eb784883d3dc9d0d74a74633f067dc61c408dfdee49b8f93bb161f2916c0208e11eb784883d3dc9d0d74a74633f067dc61c408dfdee49b8f93bb161f2916c0013085ae9000f50f53adb25405b339df3a86c180a2312ba857d94c077e474a3a577e3dc4eb53a0cd2b1b1e880383d3680af80c35322e38392e3135342e3438146d57707c196e06487d326094c964f258f5b77c35fb4e1ffb05a3fb8f3000208eca4bcbb3a124ab283afd42dad3bdb2077b3809659788a0f1daffce5b9f001f208eca4bcbb3a124ab283afd42dad3bdb2077b3809659788a0f1daffce5b9f001f0130a8534f9a11dda86ea001342d7166778b70849462281cf7a5f92bcb82044900b5abb42f7301ff900e62915898bf8835710d35342e36382e3233352e32303114c075993a8336f93a13bb7bbb7e0e89928be4aafbfb4e1ffb05a3fb8f30002091bbce94c34ebde0d099c0a2cb7635c0c31425ebabcec644f4f1a0854bfa605d2091bbce94c34ebde0d099c0a2cb7635c0c31425ebabcec644f4f1a0854bfa605d0130b080fa15ef37262f5c499bdf9c9487a0e8f3419c3a809aa794af4cae7cde22052eb8323559da812edce33431f0d826020c35322e34302e3231392e34311402aa69f8ef6666e7cad6d9323755a0ef3c1b6bd9fb4e1ffb05a3fb8f30002098ef58c338a0a68e4f2f1d1ee9eb05fcafbb9177d192dac0f698d3d9ba0920962098ef58c338a0a68e4f2f1d1ee9eb05fcafbb9177d192dac0f698d3d9ba0920960130add41989d620cc7df4eafbc7b268d334953c1e8ba5608f454c9d0a427b58721950c46f79c0b22038b12eebc7e6ec83100c34342e3233322e3139362e3614d6ece912cbf02627a4efc3dd37e6833cf3671551fb4e1ffb05a3fb8f300020b3b5748571b60fe9ad112715d6a51725d6e5a52a9c3af5fd36a1724cf50d862f20b3b5748571b60fe9ad112715d6a51725d6e5a52a9c3af5fd36a1724cf50d862f0130872c5ed02a4b12f4131bd64f4c59271102507c9a96dbd531b35cf3c1d10b285b8edb0dc6d6f641c5868f1ec065ab08050b35322e34332e31332e39321441b308f737ca9e39f67b553158903198a88c516efb4e1ffb05a3fb8f300020ba8ce1dc72857b4168e33272571df7fbaf84c316dfe48217addcf6595e25421620ba8ce1dc72857b4168e33272571df7fbaf84c316dfe48217addcf6595e2542160130b0c7d63093cb1972c8aa94c78045cff4973d79ae141365aa6392aba6939d7cf6f5a7395fc57ac6045781acaae05f67cd0d35322e34322e3230322e3132381462e0104ce0aafc1f06bde37c73702fe84b307f05fb4e1ffb05a3fb8f300020c11c1168dcf9479475cb1355855e30ea75c0cdda8a8f9ea80591568dd1c33ba820c11c1168dcf9479475cb1355855e30ea75c0cdda8a8f9ea80591568dd1c33ba8013092ae2a2792e73608a20d7b12888d2582d6647b43eb8ee8f61e09e9520732dfdd7160dfe5c6f3386a32955171b59e9b230d35342e3231332e3230342e383514fdae7cdf38811659ce9481975b326a5d07236bc5fb4e1ffb05a3fb8f300020ff261d2c1c76907a2ad8aeb6c5611796f03b5cbd88ae92452a4727e13f4f4ac920ff261d2c1c76907a2ad8aeb6c5611796f03b5cbd88ae92452a4727e13f4f4ac9013086abcf53a568276f5dace92dbdaf038d5f959742360527941a2e3b320334bff61c9e36af902b6332e667d54b4e43f20f0d35342e3138372e31342e3233321467e05b1b52c7c896adf20035036fe1d30dcefc9cfb4e1ffb05a3fb8f3000308624b652c48f38d61cda305260bff8d679d8d4194d3f94263f4be2b109b459fd257d09b21daea3ce5d607f5cf329fcc020000001d6bd1fcac1f64325a6a26b0a3a02d1e3b61267d50f855984a873c3d6890020000001d6bd1fcac1f64325a6a26b0a3a02d1e3b61267d50f855984a873c3d68900fc001109a0192005b687978344fa2433b2aa99d41f643e2d8581a789cdc23084889ceca5244ea82005b687978344fa2433b2aa99d41f643e2d8581a789cdc23084889ceca5244ea80130801d1caeb0249874c51e6aef9c319b3260af3a7f4abd77e44f7f2794be2b1f1211ac2e06d951dc1102541944767bf70b0d35322e32342e3132342e313632148feb00404d6f765856c95e587b2523a365bc7258fb4e1ffb05a3fb8f30002012de3ea6678dadb1db529b7fa98762160625055de2aa34e757c93c136233f4a22012de3ea6678dadb1db529b7fa98762160625055de2aa34e757c93c136233f4a201308959077c75d865f18eb0e6da55e1685c071b16b2ebc6ae717d9ecb15c40783a22cfc80283ec15b1b58d011f5d211de470e3231322e32342e3130332e31343914c1161c96de3dae28cd7f20ff8c2aa7b94b866d76fb4e1ffb05a3fb8f300020143dcd6a6b7684fde01e88a10e5d65de9a29244c5ecd586d14a342657025f11320143dcd6a6b7684fde01e88a10e5d65de9a29244c5ecd586d14a342657025f1130130964add28e4e033a83073203713210ba9451300e370901e24c64c170c9c714df36bcdfee02c6358c7e9348cc2193c1c790d33352e3136342e32332e32343514b5f25f8f70cf8d05c2d2970bdf186c994431d84efb4e1ffb05a3fb8f3000202e48651a2e9c0cb4f2fb7ab874061aa4af0cd28b59695631e6a35af3950ef6fb202e48651a2e9c0cb4f2fb7ab874061aa4af0cd28b59695631e6a35af3950ef6fb01308dd74a742631dd039ae8b11e2f3f2f1fc2503ba590ee5487a9af71d4713c0b7df9c91e730f246c5b012d682623bfe5980d35342e3134392e33332e313637141ffbf1d32541dcb8f5555305295704a9ff9adc24fb4e1ffb05a3fb8f3000203971dab9691efac06e4ce7a5483131373e84726458924fe48b7d541791693be1203971dab9691efac06e4ce7a5483131373e84726458924fe48b7d541791693be10130839b06bd3faa0249a1de9e490de0ae9b1f687f01748000720b6181271185e83deb5ee39085aacb7a19164e2c7995b9510d39322e36332e3137362e3230321461c274080f47a95be5372ef8c69bb60ab1d4ca82fb4e1ffb05a3fb8f30002039741ad83dd791e1e738f19edae82d6c0322972e6a455981424da3769b3dbd4a2039741ad83dd791e1e738f19edae82d6c0322972e6a455981424da3769b3dbd4a01308ad035bbe534c684bcc4edd241a3ae3710ff2484e4cbfdd7e2778574a4a10a038716232d4645f6a0986116156930da2d0e33352e3136332e3134342e32333014ec7bf3b9bc72eda38c80bb7cf16e294e763e56b4fb4e1ffb05a3fb8f30002040784f3f9a761c60156f9244a902c0626f8bc8fe003786c70f1fc6be41da467d2040784f3f9a761c60156f9244a902c0626f8bc8fe003786c70f1fc6be41da467d0130a48d35c8976bdb0d6feaed8a7fafecd6c9790eca8cc5a1e576e1ab1081caaddc5d35dbed22462b065da699d9796470030c35322e31302e3232392e3131143e8b10646ee9d6c28d75c280b357dd3a9ae9f962fb4e1ffb05a3fb8f3000205b246080ba64350685fe302d3d790f5bb238cb619920d46230c844f079944a23205b246080ba64350685fe302d3d790f5bb238cb619920d46230c844f079944a2301309761664a2d48424101e4d22d0ddb7bf68a1a51d10278418bfa86125eddbf53a73116d8e11d35fc56dcdf7dd1cbc198340d33352e3136352e35302e31323614f460a07a2b0dc932e1d8ff2dee2b984ac415dcebfb4e1ffb05a3fb8f3000205c6542766615387183715d958a925552472f93335fa1612880423e4bbdaef436205c6542766615387183715d958a925552472f93335fa1612880423e4bbdaef43601309444afcc0ef76d51219a693687d3373ae2d63cf0f2982ac364cde53ea5f3f4aad1abd2e9236848dd229fcc7bd461f4e70d34342e3233392e33392e31353314972a33056d57359de8acfa4fb8b29dc1c14f76b8fb4e1ffb05a3fb8f30002061d33f478933797be4de88353c7c2d843c21310f6d00f6eff31424a756ee7dfb2061d33f478933797be4de88353c7c2d843c21310f6d00f6eff31424a756ee7dfb01308f6f64001871f148e8f2befa5562d682e5ea35b15d651c1e5632a9ec007897ae1accdb7c771935efaadb053584f0f0ec0c35322e31322e3137362e3930147ada3e486409b39c94a0833c8d782f35bc24e96afb4e1ffb05a3fb8f3000206d1b185ba036efcd44a77e05a9aaf69a0c4e40976aec00b04773e52863320966206d1b185ba036efcd44a77e05a9aaf69a0c4e40976aec00b04773e528633209660130b2bdf73ed77b5ee1eba76d9597269b9acb54c53483f48d8a96724a8d41c77a7b54853ef41561c95823ae001fe226cd070e34342e3232382e3234322e31383114c374f016ea61e76aab79b8bb95a1ba0e6e3eee6ffb4e1ffb05a3fb8f3000207135069642e1a72807a383fb5a14b9af6758292fee53fe2a7f7ac6f528bf7019207135069642e1a72807a383fb5a14b9af6758292fee53fe2a7f7ac6f528bf70190130ac23ec29fa032506a8a1f534c0dbbfe234ab8c4a2492c6513a7a0cf8b9ba8ee80c2b8677acbe1005e9552608eef4c74f0d35342e3138392e3136342e333914f9956e70daffa263e8cf29fa6557b7b630a595a8fb4e1ffb05a3fb8f300020754b89dae8db20fc4cee5e3adb07b146d7efe508a66fa0a8e1094675b9daa35e20754b89dae8db20fc4cee5e3adb07b146d7efe508a66fa0a8e1094675b9daa35e0130a806786c7e246db9861c45ddbc16849415da9abbca80b2a92f07aa09b19c258598c62dce654153b5815b50ce21506e970c34342e3233332e34342e39351446d938862af6d9a291e26c0048177db2892a710bfb4e1ffb05a3fb8f30002085f15a31d3838293a9c1d72a1a0fa21e66110ce20878bd4c1024c4ae1d5be8242085f15a31d3838293a9c1d72a1a0fa21e66110ce20878bd4c1024c4ae1d5be824013091096939bbbc3b696e76a7def9734e8afd250c49b307930f2be484a5cfb353cfb08aee953809cfa8e25138c9230bece70d35342e3230312e33322e3133311468c506d43816d1a8389c860c1d162be44d1e777cfb4e1ffb05a3fb8f30002087075234ac47353b42bb97ce46330cb67cd4648c01f0b2393d7e729b0d6789182087075234ac47353b42bb97ce46330cb67cd4648c01f0b2393d7e729b0d6789180130a64af69f8174bf8a7f8398cba7e349b62b2fd2ecf61446a10a16a9e71cd67c8f2eb725d4cbd1c2081a5200cc2016e74a0e33352e3136372e3134352e313439149b9cdbfe3568cc0b37f136b00a634c75653f05e3fb4e1ffb05a3fb8f30002088251bd4b124efeb87537deabeec54f6c8f575f4df81f10cf5e8eea073092b6f2088251bd4b124efeb87537deabeec54f6c8f575f4df81f10cf5e8eea073092b6f01308e7b3b55424d3b06d8aa1c4ca3af5de96b8af54adb860d22f6b857cf836038ef9b711dc3a1c47cb0f0bd31e553904de50b35322e33332e32382e343714711fd9548ae19b2e91c7a9b4067000467ccdd2b5fb4e1ffb05a3fb8f3000208917bb546318f3410d1a7901c7b846a73446311b5164b45a03f0e613f208f234208917bb546318f3410d1a7901c7b846a73446311b5164b45a03f0e613f208f23401308d003529801f709ead3ed646f86e29eefd3563fd10eb48c5814929970e48691da65986d9d798cb084b085327e3e2210e0d35322e31332e3133322e313436145bdbf34a0dad860c6ec71523ae39373325225cc1fb4e1ffb05a3fb8f3000208b8d1193afd22e538ce0c9fb50fee155d0f6176ca68e65da684c5dce2d1e0815208b8d1193afd22e538ce0c9fb50fee155d0f6176ca68e65da684c5dce2d1e08150130b5d56dbd660b42d9c79be5d94912c86001c7c0118508e90ea71113f81b7ef412a56ed53bf635f8463495db374ad105b20c35322e33342e3134342e353014a0a0e17bfe82a484fefe348b7569a6d77d29d2c2fb4e1ffb05a3fb8f3000208de8b12952f7058d827bd04cdff1c2175d87bbf89f28b52452a637bc979addc4208de8b12952f7058d827bd04cdff1c2175d87bbf89f28b52452a637bc979addc4013091557309e257281d2910e7914b80bb4cfa78a74530d8c0a54b088ca244380e3f248f95e3d716b2e8043d0e74d3c362460c35322e34332e38362e32333114337b7fb5d2c531825c3e0123ac3354018085b302fb4e1ffb05a3fb8f3000208e11eb784883d3dc9d0d74a74633f067dc61c408dfdee49b8f93bb161f2916c0208e11eb784883d3dc9d0d74a74633f067dc61c408dfdee49b8f93bb161f2916c00130874f7d242343c8a96748110a12dbb246a3fcc772e25e1ad6a7dcae333ae99c205c9a85ef73441097f8b88ff2253bdb680c35322e38392e3135342e3438146d57707c196e06487d326094c964f258f5b77c35fb4e1ffb05a3fb8f30002091bbce94c34ebde0d099c0a2cb7635c0c31425ebabcec644f4f1a0854bfa605d2091bbce94c34ebde0d099c0a2cb7635c0c31425ebabcec644f4f1a0854bfa605d01308bc0894362a31bb574775fb54873f6f4b231df32e8142bc2f18839bfb54422df8f6295590fc51fab1c27040c2b34b51a0c35322e34302e3231392e34311402aa69f8ef6666e7cad6d9323755a0ef3c1b6bd9fb4e1ffb05a3fb8f3000209712e85d660fa2f761f980ef5812c225f33f336f285728803dcd421937d3df54209712e85d660fa2f761f980ef5812c225f33f336f285728803dcd421937d3df5401308ccc32d24ef5626ddcd2b28e9736617e4674fe9108af2a67f3ab4d88857d8e932cad9abe7f37a81cb42e00b5a23924c20d33352e38322e3139372e31393714ed1131823bcea23ac78af8c01e4d24683d6ecf88fb4e1ffb05a3fb8f300020ba8ce1dc72857b4168e33272571df7fbaf84c316dfe48217addcf6595e25421620ba8ce1dc72857b4168e33272571df7fbaf84c316dfe48217addcf6595e2542160130b12d38eb7f5de9b145b9f9e14e97e0e624ff91e61c9ef66e50366df4439e1f5936494e12b4216352919679e4d759c0e00d35322e34322e3230322e3132381462e0104ce0aafc1f06bde37c73702fe84b307f05fb4e1ffb05a3fb8f300020c11c1168dcf9479475cb1355855e30ea75c0cdda8a8f9ea80591568dd1c33ba820c11c1168dcf9479475cb1355855e30ea75c0cdda8a8f9ea80591568dd1c33ba801308654755a932cc93d963a2d802cabae33db99828405fe03a3838f73a05ae88c0733f9170f77f92b66d3291d7c8675dc6b0d35342e3231332e3230342e383514fdae7cdf38811659ce9481975b326a5d07236bc5fb4e1ffb05a3fb8f300020f6496d3c0ac1ad94ff5e3aab2edcabc1c8ba3fbfea0ef3026e90ba786399038120f6496d3c0ac1ad94ff5e3aab2edcabc1c8ba3fbfea0ef3026e90ba7863990381013084980eccb0d1103b2ca52e2180e96c26b287ff0dbe1038e495bb6e77bfe339a5890f7d3c10c40aa756c72c1349dd27be0d35322e31332e3235302e31383214fe2d4798df3e9b41a6823bc0b3f020478e87925dfb4e1ffb05a3fb8f30003087087556f670d7bc712e350d4b5afbf9ef0224447ac207a2ee76e040c468605d8b9cabbabe620278d01a8da30ee7026b20000000b6ebee5a8f801f7b66c32a3454b12513c76ab58b121a4e9c579bcd4e8c0020000000b6ebee5a8f801f7b66c32a3454b12513c76ab58b121a4e9c579bcd4e8c00fc00110988192005b687978344fa2433b2aa99d41f643e2d8581a789cdc23084889ceca5244ea82005b687978344fa2433b2aa99d41f643e2d8581a789cdc23084889ceca5244ea80130a703c06bb0c06e1af4dc7396d1f19f8959c5a56e99717647a91b65cc8aa543fd700b7ec561e3050ef9e868104f3c6b790d35322e32342e3132342e313632148feb00404d6f765856c95e587b2523a365bc7258fb4e1ffb05a3fb8f30002012de3ea6678dadb1db529b7fa98762160625055de2aa34e757c93c136233f4a22012de3ea6678dadb1db529b7fa98762160625055de2aa34e757c93c136233f4a20130a324d275351dad7c90e3a9a94f6efbd8ea6b865f34a09a20fb82ed55134c45982f798e26a4e80e1fb0a8c50813b86d280e3231322e32342e3130332e31343914c1161c96de3dae28cd7f20ff8c2aa7b94b866d76fb4e1ffb05a3fb8f300020143dcd6a6b7684fde01e88a10e5d65de9a29244c5ecd586d14a342657025f11320143dcd6a6b7684fde01e88a10e5d65de9a29244c5ecd586d14a342657025f1130130ad5a967b04be6266f12c245cb62edb02873a37f72d2de496d8d1f1cc92905786be7aa7c24c7941ca80b11675f44fd48f0d33352e3136342e32332e32343514b5f25f8f70cf8d05c2d2970bdf186c994431d84efb4e1ffb05a3fb8f30002020107ec50e81880dca18178bb7e53e2d0449c0734106a607253b9af2ffea006c2020107ec50e81880dca18178bb7e53e2d0449c0734106a607253b9af2ffea006c01308aa08b567a66acb8356e54f688575350edd7f2d9efa7e1c9a3897011f83caa03a7deac4146592b8ca527263332e4d0840c33352e38352e32312e3137391435d9eb76397d05b43b5cd8da7ccfa8408bc89ab3fb4e1ffb05a3fb8f3000202e48651a2e9c0cb4f2fb7ab874061aa4af0cd28b59695631e6a35af3950ef6fb202e48651a2e9c0cb4f2fb7ab874061aa4af0cd28b59695631e6a35af3950ef6fb0130ac508c0feb7d9b38e641298a71e6f10f3a8a30fa42c01856b6cfded1b452d802b6196e4b66602ea8cfafae03a37e57a00d35342e3134392e33332e313637141ffbf1d32541dcb8f5555305295704a9ff9adc24fb4e1ffb05a3fb8f30002040784f3f9a761c60156f9244a902c0626f8bc8fe003786c70f1fc6be41da467d2040784f3f9a761c60156f9244a902c0626f8bc8fe003786c70f1fc6be41da467d0130940b0a12e79c9c2b8889e6cf84f1d2c64277587471a8eecd7abec19c9f9a558791199c8fc6f07abd9b0459527e9625fd0c35322e31302e3232392e3131143e8b10646ee9d6c28d75c280b357dd3a9ae9f962fb4e1ffb05a3fb8f3000205b246080ba64350685fe302d3d790f5bb238cb619920d46230c844f079944a23205b246080ba64350685fe302d3d790f5bb238cb619920d46230c844f079944a230130b32376df0aa47f5bc41d383d00ba171eae10e87eb5dec1ffa8cb498dacdf98462e3f562e8c4901acde83da95d0d454780d33352e3136352e35302e31323614f460a07a2b0dc932e1d8ff2dee2b984ac415dcebfb4e1ffb05a3fb8f3000205c6542766615387183715d958a925552472f93335fa1612880423e4bbdaef436205c6542766615387183715d958a925552472f93335fa1612880423e4bbdaef4360130a50f2b1af92150d81387393503c15a485518b8375578b721e52bd84b1124e9a265e985681eb76e15c6a478d5b529f5ed0d34342e3233392e33392e31353314972a33056d57359de8acfa4fb8b29dc1c14f76b8fb4e1ffb05a3fb8f30002061d33f478933797be4de88353c7c2d843c21310f6d00f6eff31424a756ee7dfb2061d33f478933797be4de88353c7c2d843c21310f6d00f6eff31424a756ee7dfb0130b4c6e2f51056f17dc3cce763ea819a77770edc7122c39e68a0d8629ea8f36937468761952d9fca90a7c2c7f78f8b85770c35322e31322e3137362e3930147ada3e486409b39c94a0833c8d782f35bc24e96afb4e1ffb05a3fb8f3000206d1b185ba036efcd44a77e05a9aaf69a0c4e40976aec00b04773e52863320966206d1b185ba036efcd44a77e05a9aaf69a0c4e40976aec00b04773e52863320966013080266707faf18059f5040438724f9f46921d5f600dd837dc1aea1f08f3dc2a7d12247a3ca0feff3ebde6855e221503c30e34342e3232382e3234322e31383114c374f016ea61e76aab79b8bb95a1ba0e6e3eee6ffb4e1ffb05a3fb8f3000207135069642e1a72807a383fb5a14b9af6758292fee53fe2a7f7ac6f528bf7019207135069642e1a72807a383fb5a14b9af6758292fee53fe2a7f7ac6f528bf70190130976e8ee23029edeaae45c1737a2ab7e440145fc145a2410aff4a0735335c6d73320c6dc5425449c00458fe214f10f0c70d35342e3138392e3136342e333914f9956e70daffa263e8cf29fa6557b7b630a595a8fb4e1ffb05a3fb8f30002085f15a31d3838293a9c1d72a1a0fa21e66110ce20878bd4c1024c4ae1d5be8242085f15a31d3838293a9c1d72a1a0fa21e66110ce20878bd4c1024c4ae1d5be8240130b311bf70f84c1332681af71fe6d684933be12807de50e6a3eed260d649891e3b409c75fff910381db43f5e5cc3eec96b0d35342e3230312e33322e3133311468c506d43816d1a8389c860c1d162be44d1e777cfb4e1ffb05a3fb8f30002087075234ac47353b42bb97ce46330cb67cd4648c01f0b2393d7e729b0d6789182087075234ac47353b42bb97ce46330cb67cd4648c01f0b2393d7e729b0d6789180130a57c0905911f436b83521d87ef76513c25e1c7177050b62ce038c0c485c7d7286b86822a1db20ee50e14c7bbca115e2f0e33352e3136372e3134352e313439149b9cdbfe3568cc0b37f136b00a634c75653f05e3fb4e1ffb05a3fb8f30002088251bd4b124efeb87537deabeec54f6c8f575f4df81f10cf5e8eea073092b6f2088251bd4b124efeb87537deabeec54f6c8f575f4df81f10cf5e8eea073092b6f0130b642e74f36ecfc0984377db6259e30010d61d4b4b309668af59718d570c8f9f253baa2ac00dc6041b12c79b77eb646af0b35322e33332e32382e343714711fd9548ae19b2e91c7a9b4067000467ccdd2b5fb4e1ffb05a3fb8f3000208917bb546318f3410d1a7901c7b846a73446311b5164b45a03f0e613f208f234208917bb546318f3410d1a7901c7b846a73446311b5164b45a03f0e613f208f2340130b5f63cf0be89e8e46af538e71e1a98d33173f83131572bff054c5fc3855fdd8f4d2359b91f164a082f65232960a6bb8b0d35322e31332e3133322e313436145bdbf34a0dad860c6ec71523ae39373325225cc1fb4e1ffb05a3fb8f3000208b8d1193afd22e538ce0c9fb50fee155d0f6176ca68e65da684c5dce2d1e0815208b8d1193afd22e538ce0c9fb50fee155d0f6176ca68e65da684c5dce2d1e08150130a201efcc30db8655f99be543485d749efaaf164e222370f9dd50a3ecb0a428a07a16f7d9f9d7be5182e0974f926405f20c35322e33342e3134342e353014a0a0e17bfe82a484fefe348b7569a6d77d29d2c2fb4e1ffb05a3fb8f3000208de8b12952f7058d827bd04cdff1c2175d87bbf89f28b52452a637bc979addc4208de8b12952f7058d827bd04cdff1c2175d87bbf89f28b52452a637bc979addc40130b54279aae2009b7651c29c87d6a00bace24b0112690401ac71c935ba79c637ebab1dd1b6c8e5dd70c002846b87c580430c35322e34332e38362e32333114337b7fb5d2c531825c3e0123ac3354018085b302fb4e1ffb05a3fb8f3000208eca4bcbb3a124ab283afd42dad3bdb2077b3809659788a0f1daffce5b9f001f208eca4bcbb3a124ab283afd42dad3bdb2077b3809659788a0f1daffce5b9f001f01308b55bd02dd900fc8f513373fc4275474e3c64f489463a2d167d93eb81cd6e41c54f06554d280ac71bd80b12f93c386e30d35342e36382e3233352e32303114c075993a8336f93a13bb7bbb7e0e89928be4aafbfb4e1ffb05a3fb8f30002091bbce94c34ebde0d099c0a2cb7635c0c31425ebabcec644f4f1a0854bfa605d2091bbce94c34ebde0d099c0a2cb7635c0c31425ebabcec644f4f1a0854bfa605d0130b847c83b10bac91203bd0ffbdee778131803975467db2d0889defa1f4671ab9207d330e944772f7ac7b7b05c04b59d5c0c35322e34302e3231392e34311402aa69f8ef6666e7cad6d9323755a0ef3c1b6bd9fb4e1ffb05a3fb8f3000209cb04f271ba050132c00cc5838fb69e77bc55b5689f9d2d850dc528935f8145c209cb04f271ba050132c00cc5838fb69e77bc55b5689f9d2d850dc528935f8145c0130a76f59dad02d335374150895bcda911a1c8f77fc49938a60fc913ac1b01dca06eaf67c34145efa68f02d8ed5aacf60980c33342e3231342e34382e36381462e960a3f6b650feed98a266b3ccdf6e363562cffb4e1ffb05a3fb8f300020ba8ce1dc72857b4168e33272571df7fbaf84c316dfe48217addcf6595e25421620ba8ce1dc72857b4168e33272571df7fbaf84c316dfe48217addcf6595e2542160130a510330a7be7301de1872e3fb864ce4a6d9e6faad494159a5a29476c7110dc8fa10921c63d3e93f4181845c7fabd2c7f0d35322e34322e3230322e3132381462e0104ce0aafc1f06bde37c73702fe84b307f05fb4e1ffb05a3fb8f300020bbfd0ac1977011267a7032641ef5487fe15a4de798faa485b156fb3b7eb0acb820bbfd0ac1977011267a7032641ef5487fe15a4de798faa485b156fb3b7eb0acb80130b29f367ac0aa1c4a047507c039c7b406ddd38256b55fcc636ed00badef8240e50905b96d810b2eefc2ff0a82d0434a5f0c33352e38322e34392e31393614dbbebbc52a5bae21b818e0487311041c91b2683bfb4e1ffb05a3fb8f300020c11c1168dcf9479475cb1355855e30ea75c0cdda8a8f9ea80591568dd1c33ba820c11c1168dcf9479475cb1355855e30ea75c0cdda8a8f9ea80591568dd1c33ba80130b04058eaf4d337cdc95914d77fbc9f22be1dadd3fce162bf4bf3f67372383b7cc287eef82634ba9f69182c9e615b83ce0d35342e3231332e3230342e383514fdae7cdf38811659ce9481975b326a5d07236bc5fb4e1ffb05a3fb8f300020f6496d3c0ac1ad94ff5e3aab2edcabc1c8ba3fbfea0ef3026e90ba786399038120f6496d3c0ac1ad94ff5e3aab2edcabc1c8ba3fbfea0ef3026e90ba78639903810130a190aad82d3d99b77ba2ec6019caa72e82575fb72cf05d9eb97ef0f8d3f088c7350fbeb19c8a13c95f7e68073ef64fb20d35322e31332e3235302e31383214fe2d4798df3e9b41a6823bc0b3f020478e87925dfb4e1ffb05a3fb8f300020ff261d2c1c76907a2ad8aeb6c5611796f03b5cbd88ae92452a4727e13f4f4ac920ff261d2c1c76907a2ad8aeb6c5611796f03b5cbd88ae92452a4727e13f4f4ac901308d0c12f1fc8ee77846153c42e78d2e420358de9478058680d0c1019b33e65b1da765e8a369620e06145a573f46d5d6a70d35342e3138372e31342e3233321467e05b1b52c7c896adf20035036fe1d30dcefc9cfb4e1ffb05a3fb8f300030a6ece569edd51a503a2cfe5b2be0e24c33179ee6f8afa152d185b19f87fccb8ce5ecff6300fc600bd0418b69dcc3f4f220000000e78672b7a792c03ffc5e06c6512e0ae64c4b5410a2e41b6b871036e5d30020000000e78672b7a792c03ffc5e06c6512e0ae64c4b5410a2e41b6b871036e5d300fc00110970192005b687978344fa2433b2aa99d41f643e2d8581a789cdc23084889ceca5244ea82005b687978344fa2433b2aa99d41f643e2d8581a789cdc23084889ceca5244ea8000d35322e32342e3132342e313632148feb00404d6f765856c95e587b2523a365bc7258fb4e1ffb05a3fb8f30002012de3ea6678dadb1db529b7fa98762160625055de2aa34e757c93c136233f4a22012de3ea6678dadb1db529b7fa98762160625055de2aa34e757c93c136233f4a2000e3231322e32342e3130332e31343914c1161c96de3dae28cd7f20ff8c2aa7b94b866d76fb4e1ffb05a3fb8f30002020107ec50e81880dca18178bb7e53e2d0449c0734106a607253b9af2ffea006c2020107ec50e81880dca18178bb7e53e2d0449c0734106a607253b9af2ffea006c000c33352e38352e32312e3137391435d9eb76397d05b43b5cd8da7ccfa8408bc89ab3fb4e1ffb05a3fb8f30002039741ad83dd791e1e738f19edae82d6c0322972e6a455981424da3769b3dbd4a2039741ad83dd791e1e738f19edae82d6c0322972e6a455981424da3769b3dbd4a000e33352e3136332e3134342e32333014ec7bf3b9bc72eda38c80bb7cf16e294e763e56b4fb4e1ffb05a3fb8f30002040784f3f9a761c60156f9244a902c0626f8bc8fe003786c70f1fc6be41da467d2040784f3f9a761c60156f9244a902c0626f8bc8fe003786c70f1fc6be41da467d000c35322e31302e3232392e3131143e8b10646ee9d6c28d75c280b357dd3a9ae9f962fb4e1ffb05a3fb8f30002061d33f478933797be4de88353c7c2d843c21310f6d00f6eff31424a756ee7dfb2061d33f478933797be4de88353c7c2d843c21310f6d00f6eff31424a756ee7dfb000c35322e31322e3137362e3930147ada3e486409b39c94a0833c8d782f35bc24e96afb4e1ffb05a3fb8f3000206d1b185ba036efcd44a77e05a9aaf69a0c4e40976aec00b04773e52863320966206d1b185ba036efcd44a77e05a9aaf69a0c4e40976aec00b04773e52863320966000e34342e3232382e3234322e31383114c374f016ea61e76aab79b8bb95a1ba0e6e3eee6ffb4e1ffb05a3fb8f3000207135069642e1a72807a383fb5a14b9af6758292fee53fe2a7f7ac6f528bf7019207135069642e1a72807a383fb5a14b9af6758292fee53fe2a7f7ac6f528bf7019000d35342e3138392e3136342e333914f9956e70daffa263e8cf29fa6557b7b630a595a8fb4e1ffb05a3fb8f300020754b89dae8db20fc4cee5e3adb07b146d7efe508a66fa0a8e1094675b9daa35e20754b89dae8db20fc4cee5e3adb07b146d7efe508a66fa0a8e1094675b9daa35e000c34342e3233332e34342e39351446d938862af6d9a291e26c0048177db2892a710bfb4e1ffb05a3fb8f3000207718edad371e46d20fad30086e4acf4a05c2b660df6ae5f2a684aebdf1be4290207718edad371e46d20fad30086e4acf4a05c2b660df6ae5f2a684aebdf1be4290000d34342e3232372e3133372e3737140498ade3c80045c2a7520e921180ae1c39da5c57fb4e1ffb05a3fb8f30002085f15a31d3838293a9c1d72a1a0fa21e66110ce20878bd4c1024c4ae1d5be8242085f15a31d3838293a9c1d72a1a0fa21e66110ce20878bd4c1024c4ae1d5be824000d35342e3230312e33322e3133311468c506d43816d1a8389c860c1d162be44d1e777cfb4e1ffb05a3fb8f30002087075234ac47353b42bb97ce46330cb67cd4648c01f0b2393d7e729b0d6789182087075234ac47353b42bb97ce46330cb67cd4648c01f0b2393d7e729b0d678918000e33352e3136372e3134352e313439149b9cdbfe3568cc0b37f136b00a634c75653f05e3fb4e1ffb05a3fb8f30002088251bd4b124efeb87537deabeec54f6c8f575f4df81f10cf5e8eea073092b6f2088251bd4b124efeb87537deabeec54f6c8f575f4df81f10cf5e8eea073092b6f000b35322e33332e32382e343714711fd9548ae19b2e91c7a9b4067000467ccdd2b5fb4e1ffb05a3fb8f3000208917bb546318f3410d1a7901c7b846a73446311b5164b45a03f0e613f208f234208917bb546318f3410d1a7901c7b846a73446311b5164b45a03f0e613f208f234000d35322e31332e3133322e313436145bdbf34a0dad860c6ec71523ae39373325225cc1fb4e1ffb05a3fb8f3000208b8d1193afd22e538ce0c9fb50fee155d0f6176ca68e65da684c5dce2d1e0815208b8d1193afd22e538ce0c9fb50fee155d0f6176ca68e65da684c5dce2d1e0815000c35322e33342e3134342e353014a0a0e17bfe82a484fefe348b7569a6d77d29d2c2fb4e1ffb05a3fb8f3000208de8b12952f7058d827bd04cdff1c2175d87bbf89f28b52452a637bc979addc4208de8b12952f7058d827bd04cdff1c2175d87bbf89f28b52452a637bc979addc4000c35322e34332e38362e32333114337b7fb5d2c531825c3e0123ac3354018085b302fb4e1ffb05a3fb8f3000208e11eb784883d3dc9d0d74a74633f067dc61c408dfdee49b8f93bb161f2916c0208e11eb784883d3dc9d0d74a74633f067dc61c408dfdee49b8f93bb161f2916c0000c35322e38392e3135342e3438146d57707c196e06487d326094c964f258f5b77c35fb4e1ffb05a3fb8f3000208eca4bcbb3a124ab283afd42dad3bdb2077b3809659788a0f1daffce5b9f001f208eca4bcbb3a124ab283afd42dad3bdb2077b3809659788a0f1daffce5b9f001f000d35342e36382e3233352e32303114c075993a8336f93a13bb7bbb7e0e89928be4aafbfb4e1ffb05a3fb8f30002091bbce94c34ebde0d099c0a2cb7635c0c31425ebabcec644f4f1a0854bfa605d2091bbce94c34ebde0d099c0a2cb7635c0c31425ebabcec644f4f1a0854bfa605d000c35322e34302e3231392e34311402aa69f8ef6666e7cad6d9323755a0ef3c1b6bd9fb4e1ffb05a3fb8f30002098ef58c338a0a68e4f2f1d1ee9eb05fcafbb9177d192dac0f698d3d9ba0920962098ef58c338a0a68e4f2f1d1ee9eb05fcafbb9177d192dac0f698d3d9ba092096000c34342e3233322e3139362e3614d6ece912cbf02627a4efc3dd37e6833cf3671551fb4e1ffb05a3fb8f3000209cb04f271ba050132c00cc5838fb69e77bc55b5689f9d2d850dc528935f8145c209cb04f271ba050132c00cc5838fb69e77bc55b5689f9d2d850dc528935f8145c000c33342e3231342e34382e36381462e960a3f6b650feed98a266b3ccdf6e363562cffb4e1ffb05a3fb8f300020b3b5748571b60fe9ad112715d6a51725d6e5a52a9c3af5fd36a1724cf50d862f20b3b5748571b60fe9ad112715d6a51725d6e5a52a9c3af5fd36a1724cf50d862f000b35322e34332e31332e39321441b308f737ca9e39f67b553158903198a88c516efb4e1ffb05a3fb8f300020c11c1168dcf9479475cb1355855e30ea75c0cdda8a8f9ea80591568dd1c33ba820c11c1168dcf9479475cb1355855e30ea75c0cdda8a8f9ea80591568dd1c33ba8000d35342e3231332e3230342e383514fdae7cdf38811659ce9481975b326a5d07236bc5fb4e1ffb05a3fb8f300020d9b090cfc19caf2e27d512e69c43812a274bdf29c081d0ade4fd272ad56a5f8920d9b090cfc19caf2e27d512e69c43812a274bdf29c081d0ade4fd272ad56a5f89000d34342e3234302e39382e313032147034f0d3853c5351fb8e0ffd3c1daf12c51c2d89fb4e1ffb05a3fb8f300020f6496d3c0ac1ad94ff5e3aab2edcabc1c8ba3fbfea0ef3026e90ba786399038120f6496d3c0ac1ad94ff5e3aab2edcabc1c8ba3fbfea0ef3026e90ba7863990381000d35322e31332e3235302e31383214fe2d4798df3e9b41a6823bc0b3f020478e87925dfb4e1ffb05a3fb8f300030952b5f1b8f31ad775ba1420d465e22b9db941245eacc8d738bee5b8e4704771d461a42949afe7e2ae91d49e795cf9ba22000000021160aae5b92562c94a5d6735c5dff3a92aa0a8d9b02aa0c614ca7154a002000000021160aae5b92562c94a5d6735c5dff3a92aa0a8d9b02aa0c614ca7154a00fc00110958192005b687978344fa2433b2aa99d41f643e2d8581a789cdc23084889ceca5244ea82005b687978344fa2433b2aa99d41f643e2d8581a789cdc23084889ceca5244ea8000d35322e32342e3132342e313632148feb00404d6f765856c95e587b2523a365bc7258fb4e1ffb05a3fb8f30002012de3ea6678dadb1db529b7fa98762160625055de2aa34e757c93c136233f4a22012de3ea6678dadb1db529b7fa98762160625055de2aa34e757c93c136233f4a2000e3231322e32342e3130332e31343914c1161c96de3dae28cd7f20ff8c2aa7b94b866d76fb4e1ffb05a3fb8f300020143dcd6a6b7684fde01e88a10e5d65de9a29244c5ecd586d14a342657025f11320143dcd6a6b7684fde01e88a10e5d65de9a29244c5ecd586d14a342657025f113000d33352e3136342e32332e32343514b5f25f8f70cf8d05c2d2970bdf186c994431d84efb4e1ffb05a3fb8f30002020107ec50e81880dca18178bb7e53e2d0449c0734106a607253b9af2ffea006c2020107ec50e81880dca18178bb7e53e2d0449c0734106a607253b9af2ffea006c000c33352e38352e32312e3137391435d9eb76397d05b43b5cd8da7ccfa8408bc89ab3fb4e1ffb05a3fb8f3000202e48651a2e9c0cb4f2fb7ab874061aa4af0cd28b59695631e6a35af3950ef6fb202e48651a2e9c0cb4f2fb7ab874061aa4af0cd28b59695631e6a35af3950ef6fb000d35342e3134392e33332e313637141ffbf1d32541dcb8f5555305295704a9ff9adc24fb4e1ffb05a3fb8f30002039741ad83dd791e1e738f19edae82d6c0322972e6a455981424da3769b3dbd4a2039741ad83dd791e1e738f19edae82d6c0322972e6a455981424da3769b3dbd4a000e33352e3136332e3134342e32333014ec7bf3b9bc72eda38c80bb7cf16e294e763e56b4fb4e1ffb05a3fb8f30002040784f3f9a761c60156f9244a902c0626f8bc8fe003786c70f1fc6be41da467d2040784f3f9a761c60156f9244a902c0626f8bc8fe003786c70f1fc6be41da467d000c35322e31302e3232392e3131143e8b10646ee9d6c28d75c280b357dd3a9ae9f962fb4e1ffb05a3fb8f3000205c6542766615387183715d958a925552472f93335fa1612880423e4bbdaef436205c6542766615387183715d958a925552472f93335fa1612880423e4bbdaef436000d34342e3233392e33392e31353314972a33056d57359de8acfa4fb8b29dc1c14f76b8fb4e1ffb05a3fb8f30002061d33f478933797be4de88353c7c2d843c21310f6d00f6eff31424a756ee7dfb2061d33f478933797be4de88353c7c2d843c21310f6d00f6eff31424a756ee7dfb000c35322e31322e3137362e3930147ada3e486409b39c94a0833c8d782f35bc24e96afb4e1ffb05a3fb8f3000206d1b185ba036efcd44a77e05a9aaf69a0c4e40976aec00b04773e52863320966206d1b185ba036efcd44a77e05a9aaf69a0c4e40976aec00b04773e52863320966000e34342e3232382e3234322e31383114c374f016ea61e76aab79b8bb95a1ba0e6e3eee6ffb4e1ffb05a3fb8f3000207718edad371e46d20fad30086e4acf4a05c2b660df6ae5f2a684aebdf1be4290207718edad371e46d20fad30086e4acf4a05c2b660df6ae5f2a684aebdf1be4290000d34342e3232372e3133372e3737140498ade3c80045c2a7520e921180ae1c39da5c57fb4e1ffb05a3fb8f30002088251bd4b124efeb87537deabeec54f6c8f575f4df81f10cf5e8eea073092b6f2088251bd4b124efeb87537deabeec54f6c8f575f4df81f10cf5e8eea073092b6f000b35322e33332e32382e343714711fd9548ae19b2e91c7a9b4067000467ccdd2b5fb4e1ffb05a3fb8f3000208917bb546318f3410d1a7901c7b846a73446311b5164b45a03f0e613f208f234208917bb546318f3410d1a7901c7b846a73446311b5164b45a03f0e613f208f234000d35322e31332e3133322e313436145bdbf34a0dad860c6ec71523ae39373325225cc1fb4e1ffb05a3fb8f3000208de8b12952f7058d827bd04cdff1c2175d87bbf89f28b52452a637bc979addc4208de8b12952f7058d827bd04cdff1c2175d87bbf89f28b52452a637bc979addc4000c35322e34332e38362e32333114337b7fb5d2c531825c3e0123ac3354018085b302fb4e1ffb05a3fb8f3000208e11eb784883d3dc9d0d74a74633f067dc61c408dfdee49b8f93bb161f2916c0208e11eb784883d3dc9d0d74a74633f067dc61c408dfdee49b8f93bb161f2916c0000c35322e38392e3135342e3438146d57707c196e06487d326094c964f258f5b77c35fb4e1ffb05a3fb8f3000208eca4bcbb3a124ab283afd42dad3bdb2077b3809659788a0f1daffce5b9f001f208eca4bcbb3a124ab283afd42dad3bdb2077b3809659788a0f1daffce5b9f001f000d35342e36382e3233352e32303114c075993a8336f93a13bb7bbb7e0e89928be4aafbfb4e1ffb05a3fb8f30002091bbce94c34ebde0d099c0a2cb7635c0c31425ebabcec644f4f1a0854bfa605d2091bbce94c34ebde0d099c0a2cb7635c0c31425ebabcec644f4f1a0854bfa605d000c35322e34302e3231392e34311402aa69f8ef6666e7cad6d9323755a0ef3c1b6bd9fb4e1ffb05a3fb8f3000209712e85d660fa2f761f980ef5812c225f33f336f285728803dcd421937d3df54209712e85d660fa2f761f980ef5812c225f33f336f285728803dcd421937d3df54000d33352e38322e3139372e31393714ed1131823bcea23ac78af8c01e4d24683d6ecf88fb4e1ffb05a3fb8f300020b3b5748571b60fe9ad112715d6a51725d6e5a52a9c3af5fd36a1724cf50d862f20b3b5748571b60fe9ad112715d6a51725d6e5a52a9c3af5fd36a1724cf50d862f000b35322e34332e31332e39321441b308f737ca9e39f67b553158903198a88c516efb4e1ffb05a3fb8f300020ba8ce1dc72857b4168e33272571df7fbaf84c316dfe48217addcf6595e25421620ba8ce1dc72857b4168e33272571df7fbaf84c316dfe48217addcf6595e254216000d35322e34322e3230322e3132381462e0104ce0aafc1f06bde37c73702fe84b307f05fb4e1ffb05a3fb8f300020bbfd0ac1977011267a7032641ef5487fe15a4de798faa485b156fb3b7eb0acb820bbfd0ac1977011267a7032641ef5487fe15a4de798faa485b156fb3b7eb0acb8000c33352e38322e34392e31393614dbbebbc52a5bae21b818e0487311041c91b2683bfb4e1ffb05a3fb8f300020c11c1168dcf9479475cb1355855e30ea75c0cdda8a8f9ea80591568dd1c33ba820c11c1168dcf9479475cb1355855e30ea75c0cdda8a8f9ea80591568dd1c33ba8000d35342e3231332e3230342e383514fdae7cdf38811659ce9481975b326a5d07236bc5fb4e1ffb05a3fb8f300020d9b090cfc19caf2e27d512e69c43812a274bdf29c081d0ade4fd272ad56a5f8920d9b090cfc19caf2e27d512e69c43812a274bdf29c081d0ade4fd272ad56a5f89000d34342e3234302e39382e313032147034f0d3853c5351fb8e0ffd3c1daf12c51c2d89fb4e1ffb05a3fb8f300020f6496d3c0ac1ad94ff5e3aab2edcabc1c8ba3fbfea0ef3026e90ba786399038120f6496d3c0ac1ad94ff5e3aab2edcabc1c8ba3fbfea0ef3026e90ba7863990381000d35322e31332e3235302e31383214fe2d4798df3e9b41a6823bc0b3f020478e87925dfb4e1ffb05a3fb8f300020ff261d2c1c76907a2ad8aeb6c5611796f03b5cbd88ae92452a4727e13f4f4ac920ff261d2c1c76907a2ad8aeb6c5611796f03b5cbd88ae92452a4727e13f4f4ac9000d35342e3138372e31342e3233321467e05b1b52c7c896adf20035036fe1d30dcefc9cfb4e1ffb05a3fb8f300030afe32c814088749bdf90012b78f156d0bea19ba06a56d4d6a22e80fbe9444d64c5b1545b55bb0f1c92fd79a1eae4e29d20000001561ac909f7762f03b801661c0ab46943d603d2883b36535ad5f6344cb80020000001561ac909f7762f03b801661c0ab46943d603d2883b36535ad5f6344cb800fc00110940192005b687978344fa2433b2aa99d41f643e2d8581a789cdc23084889ceca5244ea82005b687978344fa2433b2aa99d41f643e2d8581a789cdc23084889ceca5244ea8000d35322e32342e3132342e313632148feb00404d6f765856c95e587b2523a365bc7258fb4e1ffb05a3fb8f30002012de3ea6678dadb1db529b7fa98762160625055de2aa34e757c93c136233f4a22012de3ea6678dadb1db529b7fa98762160625055de2aa34e757c93c136233f4a2000e3231322e32342e3130332e31343914c1161c96de3dae28cd7f20ff8c2aa7b94b866d76fb4e1ffb05a3fb8f300020143dcd6a6b7684fde01e88a10e5d65de9a29244c5ecd586d14a342657025f11320143dcd6a6b7684fde01e88a10e5d65de9a29244c5ecd586d14a342657025f113000d33352e3136342e32332e32343514b5f25f8f70cf8d05c2d2970bdf186c994431d84efb4e1ffb05a3fb8f3000202e48651a2e9c0cb4f2fb7ab874061aa4af0cd28b59695631e6a35af3950ef6fb202e48651a2e9c0cb4f2fb7ab874061aa4af0cd28b59695631e6a35af3950ef6fb000d35342e3134392e33332e313637141ffbf1d32541dcb8f5555305295704a9ff9adc24fb4e1ffb05a3fb8f30002039741ad83dd791e1e738f19edae82d6c0322972e6a455981424da3769b3dbd4a2039741ad83dd791e1e738f19edae82d6c0322972e6a455981424da3769b3dbd4a000e33352e3136332e3134342e32333014ec7bf3b9bc72eda38c80bb7cf16e294e763e56b4fb4e1ffb05a3fb8f30002040784f3f9a761c60156f9244a902c0626f8bc8fe003786c70f1fc6be41da467d2040784f3f9a761c60156f9244a902c0626f8bc8fe003786c70f1fc6be41da467d000c35322e31302e3232392e3131143e8b10646ee9d6c28d75c280b357dd3a9ae9f962fb4e1ffb05a3fb8f3000205c6542766615387183715d958a925552472f93335fa1612880423e4bbdaef436205c6542766615387183715d958a925552472f93335fa1612880423e4bbdaef436000d34342e3233392e33392e31353314972a33056d57359de8acfa4fb8b29dc1c14f76b8fb4e1ffb05a3fb8f30002061d33f478933797be4de88353c7c2d843c21310f6d00f6eff31424a756ee7dfb2061d33f478933797be4de88353c7c2d843c21310f6d00f6eff31424a756ee7dfb000c35322e31322e3137362e3930147ada3e486409b39c94a0833c8d782f35bc24e96afb4e1ffb05a3fb8f3000206d1b185ba036efcd44a77e05a9aaf69a0c4e40976aec00b04773e52863320966206d1b185ba036efcd44a77e05a9aaf69a0c4e40976aec00b04773e52863320966000e34342e3232382e3234322e31383114c374f016ea61e76aab79b8bb95a1ba0e6e3eee6ffb4e1ffb05a3fb8f300020754b89dae8db20fc4cee5e3adb07b146d7efe508a66fa0a8e1094675b9daa35e20754b89dae8db20fc4cee5e3adb07b146d7efe508a66fa0a8e1094675b9daa35e000c34342e3233332e34342e39351446d938862af6d9a291e26c0048177db2892a710bfb4e1ffb05a3fb8f3000207718edad371e46d20fad30086e4acf4a05c2b660df6ae5f2a684aebdf1be4290207718edad371e46d20fad30086e4acf4a05c2b660df6ae5f2a684aebdf1be4290000d34342e3232372e3133372e3737140498ade3c80045c2a7520e921180ae1c39da5c57fb4e1ffb05a3fb8f30002085f15a31d3838293a9c1d72a1a0fa21e66110ce20878bd4c1024c4ae1d5be8242085f15a31d3838293a9c1d72a1a0fa21e66110ce20878bd4c1024c4ae1d5be824000d35342e3230312e33322e3133311468c506d43816d1a8389c860c1d162be44d1e777cfb4e1ffb05a3fb8f30002088251bd4b124efeb87537deabeec54f6c8f575f4df81f10cf5e8eea073092b6f2088251bd4b124efeb87537deabeec54f6c8f575f4df81f10cf5e8eea073092b6f000b35322e33332e32382e343714711fd9548ae19b2e91c7a9b4067000467ccdd2b5fb4e1ffb05a3fb8f3000208917bb546318f3410d1a7901c7b846a73446311b5164b45a03f0e613f208f234208917bb546318f3410d1a7901c7b846a73446311b5164b45a03f0e613f208f234000d35322e31332e3133322e313436145bdbf34a0dad860c6ec71523ae39373325225cc1fb4e1ffb05a3fb8f3000208b8d1193afd22e538ce0c9fb50fee155d0f6176ca68e65da684c5dce2d1e0815208b8d1193afd22e538ce0c9fb50fee155d0f6176ca68e65da684c5dce2d1e0815000c35322e33342e3134342e353014a0a0e17bfe82a484fefe348b7569a6d77d29d2c2fb4e1ffb05a3fb8f3000208de8b12952f7058d827bd04cdff1c2175d87bbf89f28b52452a637bc979addc4208de8b12952f7058d827bd04cdff1c2175d87bbf89f28b52452a637bc979addc4000c35322e34332e38362e32333114337b7fb5d2c531825c3e0123ac3354018085b302fb4e1ffb05a3fb8f3000208e11eb784883d3dc9d0d74a74633f067dc61c408dfdee49b8f93bb161f2916c0208e11eb784883d3dc9d0d74a74633f067dc61c408dfdee49b8f93bb161f2916c0000c35322e38392e3135342e3438146d57707c196e06487d326094c964f258f5b77c35fb4e1ffb05a3fb8f3000208eca4bcbb3a124ab283afd42dad3bdb2077b3809659788a0f1daffce5b9f001f208eca4bcbb3a124ab283afd42dad3bdb2077b3809659788a0f1daffce5b9f001f000d35342e36382e3233352e32303114c075993a8336f93a13bb7bbb7e0e89928be4aafbfb4e1ffb05a3fb8f3000209712e85d660fa2f761f980ef5812c225f33f336f285728803dcd421937d3df54209712e85d660fa2f761f980ef5812c225f33f336f285728803dcd421937d3df54000d33352e38322e3139372e31393714ed1131823bcea23ac78af8c01e4d24683d6ecf88fb4e1ffb05a3fb8f30002098ef58c338a0a68e4f2f1d1ee9eb05fcafbb9177d192dac0f698d3d9ba0920962098ef58c338a0a68e4f2f1d1ee9eb05fcafbb9177d192dac0f698d3d9ba092096000c34342e3233322e3139362e3614d6ece912cbf02627a4efc3dd37e6833cf3671551fb4e1ffb05a3fb8f300020b3b5748571b60fe9ad112715d6a51725d6e5a52a9c3af5fd36a1724cf50d862f20b3b5748571b60fe9ad112715d6a51725d6e5a52a9c3af5fd36a1724cf50d862f000b35322e34332e31332e39321441b308f737ca9e39f67b553158903198a88c516efb4e1ffb05a3fb8f300020bbfd0ac1977011267a7032641ef5487fe15a4de798faa485b156fb3b7eb0acb820bbfd0ac1977011267a7032641ef5487fe15a4de798faa485b156fb3b7eb0acb8000c33352e38322e34392e31393614dbbebbc52a5bae21b818e0487311041c91b2683bfb4e1ffb05a3fb8f300020c11c1168dcf9479475cb1355855e30ea75c0cdda8a8f9ea80591568dd1c33ba820c11c1168dcf9479475cb1355855e30ea75c0cdda8a8f9ea80591568dd1c33ba8000d35342e3231332e3230342e383514fdae7cdf38811659ce9481975b326a5d07236bc5fb4e1ffb05a3fb8f300020d9b090cfc19caf2e27d512e69c43812a274bdf29c081d0ade4fd272ad56a5f8920d9b090cfc19caf2e27d512e69c43812a274bdf29c081d0ade4fd272ad56a5f89000d34342e3234302e39382e313032147034f0d3853c5351fb8e0ffd3c1daf12c51c2d89fb4e1ffb05a3fb8f300020f6496d3c0ac1ad94ff5e3aab2edcabc1c8ba3fbfea0ef3026e90ba786399038120f6496d3c0ac1ad94ff5e3aab2edcabc1c8ba3fbfea0ef3026e90ba7863990381000d35322e31332e3235302e31383214fe2d4798df3e9b41a6823bc0b3f020478e87925dfb4e1ffb05a3fb8f3000308759c691df7b1ba670491acca647d6b73b22357fdd6bc666f9ff12e0b05386c9b448b2565acc758f8200037776704fd120000000c9c3825db4b9a1751e94ef41634a33e2df66e8f9ddcd56dd435232f48f0020000000c9c3825db4b9a1751e94ef41634a33e2df66e8f9ddcd56dd435232f48f00fc00110928192005b687978344fa2433b2aa99d41f643e2d8581a789cdc23084889ceca5244ea82005b687978344fa2433b2aa99d41f643e2d8581a789cdc23084889ceca5244ea80130924ad656b10ed6bb91d0e3d628dcdb849ea66d25e377f2371bfd491c40e74788c859ad024da1d5cf4949834b7e79f2ee0d35322e32342e3132342e313632148feb00404d6f765856c95e587b2523a365bc7258fb4e1ffb05a3fb8f30002012de3ea6678dadb1db529b7fa98762160625055de2aa34e757c93c136233f4a22012de3ea6678dadb1db529b7fa98762160625055de2aa34e757c93c136233f4a20130aac9ede908775e57d5b1bce4b6b7fc2b1c50c8ac8353232620e979fb669b1af81690c2739bc60f35a8958764496946280e3231322e32342e3130332e31343914c1161c96de3dae28cd7f20ff8c2aa7b94b866d76fb4e1ffb05a3fb8f300020143dcd6a6b7684fde01e88a10e5d65de9a29244c5ecd586d14a342657025f11320143dcd6a6b7684fde01e88a10e5d65de9a29244c5ecd586d14a342657025f113013083ce4eb1e593141192a2453ca0ed4cfe462af4c2f564099e1defb49bc7febbb62b5f2dfd1e64e9a57e65354df6327d1c0d33352e3136342e32332e32343514b5f25f8f70cf8d05c2d2970bdf186c994431d84efb4e1ffb05a3fb8f30002020107ec50e81880dca18178bb7e53e2d0449c0734106a607253b9af2ffea006c2020107ec50e81880dca18178bb7e53e2d0449c0734106a607253b9af2ffea006c0130adc8f74781a33cc6773cdce95d58a3c2cbe36a40c4f971987226a8027787d5ddf82bfb51dbd48023b5cfacb152029c970c33352e38352e32312e3137391435d9eb76397d05b43b5cd8da7ccfa8408bc89ab3fb4e1ffb05a3fb8f3000202e48651a2e9c0cb4f2fb7ab874061aa4af0cd28b59695631e6a35af3950ef6fb202e48651a2e9c0cb4f2fb7ab874061aa4af0cd28b59695631e6a35af3950ef6fb0130b5ac90f960f003df563d7d8dc350e26e218efbc993f9cb52a59290579da516e83a69b56dea7be3f0d29f6266b9caa2b50d35342e3134392e33332e313637141ffbf1d32541dcb8f5555305295704a9ff9adc24fb4e1ffb05a3fb8f3000205b246080ba64350685fe302d3d790f5bb238cb619920d46230c844f079944a23205b246080ba64350685fe302d3d790f5bb238cb619920d46230c844f079944a230130aa742f3326d38b837ef98fb9736469642f166926f7961859c5d01dd49bfc66904b49edabf995b8e0a3b6389387614a2c0d33352e3136352e35302e31323614f460a07a2b0dc932e1d8ff2dee2b984ac415dcebfb4e1ffb05a3fb8f3000205c6542766615387183715d958a925552472f93335fa1612880423e4bbdaef436205c6542766615387183715d958a925552472f93335fa1612880423e4bbdaef4360130976d7f5ed93385d48d42851930ed313180a8a9be816085db2763dfcc233c8cf07a78ce2f3e90a48ae48f3c6203f3766f0d34342e3233392e33392e31353314972a33056d57359de8acfa4fb8b29dc1c14f76b8fb4e1ffb05a3fb8f30002061d33f478933797be4de88353c7c2d843c21310f6d00f6eff31424a756ee7dfb2061d33f478933797be4de88353c7c2d843c21310f6d00f6eff31424a756ee7dfb013083dd7663c78d21bda4652a64bd714dc888a76b8e60da2d3cccb5530b73722ec81e67815668af7a71ed484347b60586320c35322e31322e3137362e3930147ada3e486409b39c94a0833c8d782f35bc24e96afb4e1ffb05a3fb8f3000206d1b185ba036efcd44a77e05a9aaf69a0c4e40976aec00b04773e52863320966206d1b185ba036efcd44a77e05a9aaf69a0c4e40976aec00b04773e52863320966013083bcb86817efb833569855c921422c2bf1b091def65d4ad85e19e668720c238bbfed72b10f46c2a4018acdf170007d080e34342e3232382e3234322e31383114c374f016ea61e76aab79b8bb95a1ba0e6e3eee6ffb4e1ffb05a3fb8f3000207135069642e1a72807a383fb5a14b9af6758292fee53fe2a7f7ac6f528bf7019207135069642e1a72807a383fb5a14b9af6758292fee53fe2a7f7ac6f528bf70190130971f8a04797eaaa9b3b9dd3d693cd306521e1cf500952419a34b1977d086a3df182a700b02872dff3cb290a04208a9c50d35342e3138392e3136342e333914f9956e70daffa263e8cf29fa6557b7b630a595a8fb4e1ffb05a3fb8f300020754b89dae8db20fc4cee5e3adb07b146d7efe508a66fa0a8e1094675b9daa35e20754b89dae8db20fc4cee5e3adb07b146d7efe508a66fa0a8e1094675b9daa35e013081b9ffd0d23314602ccc44eaaa8f2c40583963c2100106341900d1280850b4e84f7a31950c2279d43202348c3c857f330c34342e3233332e34342e39351446d938862af6d9a291e26c0048177db2892a710bfb4e1ffb05a3fb8f3000207718edad371e46d20fad30086e4acf4a05c2b660df6ae5f2a684aebdf1be4290207718edad371e46d20fad30086e4acf4a05c2b660df6ae5f2a684aebdf1be42900130acd93627366f7f42ef27d343f9c57a8db738e45db943c10fcd26f960a1a23a8ea25d4a3202a7ed7cc194b75f47d35c100d34342e3232372e3133372e3737140498ade3c80045c2a7520e921180ae1c39da5c57fb4e1ffb05a3fb8f30002087075234ac47353b42bb97ce46330cb67cd4648c01f0b2393d7e729b0d6789182087075234ac47353b42bb97ce46330cb67cd4648c01f0b2393d7e729b0d6789180130b6c4b5c7ce4c90a8f2c49558894d88400f82cc709c639c0331ae0e576f37548d54bdad91e49445ec9e68881cb392e9220e33352e3136372e3134352e313439149b9cdbfe3568cc0b37f136b00a634c75653f05e3fb4e1ffb05a3fb8f30002088251bd4b124efeb87537deabeec54f6c8f575f4df81f10cf5e8eea073092b6f2088251bd4b124efeb87537deabeec54f6c8f575f4df81f10cf5e8eea073092b6f013099419898f07b65df952ce60727b69493cae876e624d268710df77535afd899f6a02cdcba635b8ad3cc9842ae140e7fc90b35322e33332e32382e343714711fd9548ae19b2e91c7a9b4067000467ccdd2b5fb4e1ffb05a3fb8f3000208e11eb784883d3dc9d0d74a74633f067dc61c408dfdee49b8f93bb161f2916c0208e11eb784883d3dc9d0d74a74633f067dc61c408dfdee49b8f93bb161f2916c0013083d49c9014f9cf4a73ec9166c321ec4dffe9d7610ae2690141470fa2906dc8b8b0b65c38b881f4c87d5ba273a36476460c35322e38392e3135342e3438146d57707c196e06487d326094c964f258f5b77c35fb4e1ffb05a3fb8f30002091bbce94c34ebde0d099c0a2cb7635c0c31425ebabcec644f4f1a0854bfa605d2091bbce94c34ebde0d099c0a2cb7635c0c31425ebabcec644f4f1a0854bfa605d0130a5b2b14324b75a8f03645434878fd9b78326125ca9a5479b3a63fc9c3e269f07e0914101476f0f7a81ce74db682df2330c35322e34302e3231392e34311402aa69f8ef6666e7cad6d9323755a0ef3c1b6bd9fb4e1ffb05a3fb8f30002098ef58c338a0a68e4f2f1d1ee9eb05fcafbb9177d192dac0f698d3d9ba0920962098ef58c338a0a68e4f2f1d1ee9eb05fcafbb9177d192dac0f698d3d9ba0920960130a910e926ae8a2a9ac7130053e40ff33f8a6b05f465619eaeea156550ef956c663797d5096f7db4eb1db5bf328ba963440c34342e3233322e3139362e3614d6ece912cbf02627a4efc3dd37e6833cf3671551fb4e1ffb05a3fb8f3000209cb04f271ba050132c00cc5838fb69e77bc55b5689f9d2d850dc528935f8145c209cb04f271ba050132c00cc5838fb69e77bc55b5689f9d2d850dc528935f8145c0130ad328fa477cf797787c60fb91c2cb603896d04de19515bfa94fcf6dcd943a5dfe09f3341ca7ca0872cd8da59e68d72b10c33342e3231342e34382e36381462e960a3f6b650feed98a266b3ccdf6e363562cffb4e1ffb05a3fb8f300020b3b5748571b60fe9ad112715d6a51725d6e5a52a9c3af5fd36a1724cf50d862f20b3b5748571b60fe9ad112715d6a51725d6e5a52a9c3af5fd36a1724cf50d862f0130b123e19529c06f90a4c62c60fa86a64681ad3d93a0ada42ebc496f1643448819bed2a94b1ff5e5ff32ca3a9589fc37590b35322e34332e31332e39321441b308f737ca9e39f67b553158903198a88c516efb4e1ffb05a3fb8f300020ba8ce1dc72857b4168e33272571df7fbaf84c316dfe48217addcf6595e25421620ba8ce1dc72857b4168e33272571df7fbaf84c316dfe48217addcf6595e2542160130a3e517adf8333dfc0ae60504cfaa02dc1387a5c2d59cbf8d9cf07a84bedbea0b0b40821152f18a17529e2bf1fece004c0d35322e34322e3230322e3132381462e0104ce0aafc1f06bde37c73702fe84b307f05fb4e1ffb05a3fb8f300020bbfd0ac1977011267a7032641ef5487fe15a4de798faa485b156fb3b7eb0acb820bbfd0ac1977011267a7032641ef5487fe15a4de798faa485b156fb3b7eb0acb80130b345c75d74bd26b8c95f30eb1e23a2a892b507269f5f5416faefd7f4ce9e721210246dc074f6b2a42129a1f8dce17dfc0c33352e38322e34392e31393614dbbebbc52a5bae21b818e0487311041c91b2683bfb4e1ffb05a3fb8f300020c11c1168dcf9479475cb1355855e30ea75c0cdda8a8f9ea80591568dd1c33ba820c11c1168dcf9479475cb1355855e30ea75c0cdda8a8f9ea80591568dd1c33ba80130a556c58a4ceca86bf6e7c7cec01ecea90d9ddabc76eaa64de7e15d71ec4463d0712ddb7fc27afcf9328348e9b4555d320d35342e3231332e3230342e383514fdae7cdf38811659ce9481975b326a5d07236bc5fb4e1ffb05a3fb8f300020d9b090cfc19caf2e27d512e69c43812a274bdf29c081d0ade4fd272ad56a5f8920d9b090cfc19caf2e27d512e69c43812a274bdf29c081d0ade4fd272ad56a5f890130b97076e5170bae287a101f96a2a57c43d88d28f24c74eb3b5f19dbe8e9b0556abcaed75ff70b48f0a742afbdc32f368f0d34342e3234302e39382e313032147034f0d3853c5351fb8e0ffd3c1daf12c51c2d89fb4e1ffb05a3fb8f300020f6496d3c0ac1ad94ff5e3aab2edcabc1c8ba3fbfea0ef3026e90ba786399038120f6496d3c0ac1ad94ff5e3aab2edcabc1c8ba3fbfea0ef3026e90ba78639903810130b720e1f87cdd506feece2e0778a91d716671c7c7f19e766e5e13541074c9e053406f59816566cf4a67239d9e8101ff8d0d35322e31332e3235302e31383214fe2d4798df3e9b41a6823bc0b3f020478e87925dfb4e1ffb05a3fb8f300020ff261d2c1c76907a2ad8aeb6c5611796f03b5cbd88ae92452a4727e13f4f4ac920ff261d2c1c76907a2ad8aeb6c5611796f03b5cbd88ae92452a4727e13f4f4ac90130875fe89958bd413087ee35b99293b326b5b505482a25a3bfab04e5ac59ee2c0687c01febceffc2cc50cab76bce3cad510d35342e3138372e31342e3233321467e05b1b52c7c896adf20035036fe1d30dcefc9cfb4e1ffb05a3fb8f300030875f8e47eb3ef86e27ad3a5b0003289cdf445aed6ee7ab0f21c24e595c1f19fe9d969fdc6c5a6eeb66d712bf75846cf720000000b91e2a2fe9ab4c3899dc7d2d85c9e00e068603afe59058d5415a84773d0020000000b91e2a2fe9ab4c3899dc7d2d85c9e00e068603afe59058d5415a84773d00fc00110910192005b687978344fa2433b2aa99d41f643e2d8581a789cdc23084889ceca5244ea82005b687978344fa2433b2aa99d41f643e2d8581a789cdc23084889ceca5244ea8000d35322e32342e3132342e313632148feb00404d6f765856c95e587b2523a365bc7258fb4e1ffb05a3fb8f30002012de3ea6678dadb1db529b7fa98762160625055de2aa34e757c93c136233f4a22012de3ea6678dadb1db529b7fa98762160625055de2aa34e757c93c136233f4a2000e3231322e32342e3130332e31343914c1161c96de3dae28cd7f20ff8c2aa7b94b866d76fb4e1ffb05a3fb8f30002020107ec50e81880dca18178bb7e53e2d0449c0734106a607253b9af2ffea006c2020107ec50e81880dca18178bb7e53e2d0449c0734106a607253b9af2ffea006c000c33352e38352e32312e3137391435d9eb76397d05b43b5cd8da7ccfa8408bc89ab3fb4e1ffb05a3fb8f3000202e48651a2e9c0cb4f2fb7ab874061aa4af0cd28b59695631e6a35af3950ef6fb202e48651a2e9c0cb4f2fb7ab874061aa4af0cd28b59695631e6a35af3950ef6fb000d35342e3134392e33332e313637141ffbf1d32541dcb8f5555305295704a9ff9adc24fb4e1ffb05a3fb8f30002039741ad83dd791e1e738f19edae82d6c0322972e6a455981424da3769b3dbd4a2039741ad83dd791e1e738f19edae82d6c0322972e6a455981424da3769b3dbd4a000e33352e3136332e3134342e32333014ec7bf3b9bc72eda38c80bb7cf16e294e763e56b4fb4e1ffb05a3fb8f30002040784f3f9a761c60156f9244a902c0626f8bc8fe003786c70f1fc6be41da467d2040784f3f9a761c60156f9244a902c0626f8bc8fe003786c70f1fc6be41da467d000c35322e31302e3232392e3131143e8b10646ee9d6c28d75c280b357dd3a9ae9f962fb4e1ffb05a3fb8f3000205c6542766615387183715d958a925552472f93335fa1612880423e4bbdaef436205c6542766615387183715d958a925552472f93335fa1612880423e4bbdaef436000d34342e3233392e33392e31353314972a33056d57359de8acfa4fb8b29dc1c14f76b8fb4e1ffb05a3fb8f30002061d33f478933797be4de88353c7c2d843c21310f6d00f6eff31424a756ee7dfb2061d33f478933797be4de88353c7c2d843c21310f6d00f6eff31424a756ee7dfb000c35322e31322e3137362e3930147ada3e486409b39c94a0833c8d782f35bc24e96afb4e1ffb05a3fb8f3000206d1b185ba036efcd44a77e05a9aaf69a0c4e40976aec00b04773e52863320966206d1b185ba036efcd44a77e05a9aaf69a0c4e40976aec00b04773e52863320966000e34342e3232382e3234322e31383114c374f016ea61e76aab79b8bb95a1ba0e6e3eee6ffb4e1ffb05a3fb8f300020754b89dae8db20fc4cee5e3adb07b146d7efe508a66fa0a8e1094675b9daa35e20754b89dae8db20fc4cee5e3adb07b146d7efe508a66fa0a8e1094675b9daa35e000c34342e3233332e34342e39351446d938862af6d9a291e26c0048177db2892a710bfb4e1ffb05a3fb8f3000207718edad371e46d20fad30086e4acf4a05c2b660df6ae5f2a684aebdf1be4290207718edad371e46d20fad30086e4acf4a05c2b660df6ae5f2a684aebdf1be4290000d34342e3232372e3133372e3737140498ade3c80045c2a7520e921180ae1c39da5c57fb4e1ffb05a3fb8f30002087075234ac47353b42bb97ce46330cb67cd4648c01f0b2393d7e729b0d6789182087075234ac47353b42bb97ce46330cb67cd4648c01f0b2393d7e729b0d678918000e33352e3136372e3134352e313439149b9cdbfe3568cc0b37f136b00a634c75653f05e3fb4e1ffb05a3fb8f3000208917bb546318f3410d1a7901c7b846a73446311b5164b45a03f0e613f208f234208917bb546318f3410d1a7901c7b846a73446311b5164b45a03f0e613f208f234000d35322e31332e3133322e313436145bdbf34a0dad860c6ec71523ae39373325225cc1fb4e1ffb05a3fb8f3000208b8d1193afd22e538ce0c9fb50fee155d0f6176ca68e65da684c5dce2d1e0815208b8d1193afd22e538ce0c9fb50fee155d0f6176ca68e65da684c5dce2d1e0815000c35322e33342e3134342e353014a0a0e17bfe82a484fefe348b7569a6d77d29d2c2fb4e1ffb05a3fb8f3000208de8b12952f7058d827bd04cdff1c2175d87bbf89f28b52452a637bc979addc4208de8b12952f7058d827bd04cdff1c2175d87bbf89f28b52452a637bc979addc4000c35322e34332e38362e32333114337b7fb5d2c531825c3e0123ac3354018085b302fb4e1ffb05a3fb8f3000208e11eb784883d3dc9d0d74a74633f067dc61c408dfdee49b8f93bb161f2916c0208e11eb784883d3dc9d0d74a74633f067dc61c408dfdee49b8f93bb161f2916c0000c35322e38392e3135342e3438146d57707c196e06487d326094c964f258f5b77c35fb4e1ffb05a3fb8f3000209712e85d660fa2f761f980ef5812c225f33f336f285728803dcd421937d3df54209712e85d660fa2f761f980ef5812c225f33f336f285728803dcd421937d3df54000d33352e38322e3139372e31393714ed1131823bcea23ac78af8c01e4d24683d6ecf88fb4e1ffb05a3fb8f30002098ef58c338a0a68e4f2f1d1ee9eb05fcafbb9177d192dac0f698d3d9ba0920962098ef58c338a0a68e4f2f1d1ee9eb05fcafbb9177d192dac0f698d3d9ba092096000c34342e3233322e3139362e3614d6ece912cbf02627a4efc3dd37e6833cf3671551fb4e1ffb05a3fb8f3000209cb04f271ba050132c00cc5838fb69e77bc55b5689f9d2d850dc528935f8145c209cb04f271ba050132c00cc5838fb69e77bc55b5689f9d2d850dc528935f8145c000c33342e3231342e34382e36381462e960a3f6b650feed98a266b3ccdf6e363562cffb4e1ffb05a3fb8f300020b3b5748571b60fe9ad112715d6a51725d6e5a52a9c3af5fd36a1724cf50d862f20b3b5748571b60fe9ad112715d6a51725d6e5a52a9c3af5fd36a1724cf50d862f000b35322e34332e31332e39321441b308f737ca9e39f67b553158903198a88c516efb4e1ffb05a3fb8f300020ba8ce1dc72857b4168e33272571df7fbaf84c316dfe48217addcf6595e25421620ba8ce1dc72857b4168e33272571df7fbaf84c316dfe48217addcf6595e254216000d35322e34322e3230322e3132381462e0104ce0aafc1f06bde37c73702fe84b307f05fb4e1ffb05a3fb8f300020bbfd0ac1977011267a7032641ef5487fe15a4de798faa485b156fb3b7eb0acb820bbfd0ac1977011267a7032641ef5487fe15a4de798faa485b156fb3b7eb0acb8000c33352e38322e34392e31393614dbbebbc52a5bae21b818e0487311041c91b2683bfb4e1ffb05a3fb8f300020c11c1168dcf9479475cb1355855e30ea75c0cdda8a8f9ea80591568dd1c33ba820c11c1168dcf9479475cb1355855e30ea75c0cdda8a8f9ea80591568dd1c33ba8000d35342e3231332e3230342e383514fdae7cdf38811659ce9481975b326a5d07236bc5fb4e1ffb05a3fb8f300020d9b090cfc19caf2e27d512e69c43812a274bdf29c081d0ade4fd272ad56a5f8920d9b090cfc19caf2e27d512e69c43812a274bdf29c081d0ade4fd272ad56a5f89000d34342e3234302e39382e313032147034f0d3853c5351fb8e0ffd3c1daf12c51c2d89fb4e1ffb05a3fb8f300020f6496d3c0ac1ad94ff5e3aab2edcabc1c8ba3fbfea0ef3026e90ba786399038120f6496d3c0ac1ad94ff5e3aab2edcabc1c8ba3fbfea0ef3026e90ba7863990381000d35322e31332e3235302e31383214fe2d4798df3e9b41a6823bc0b3f020478e87925dfb4e1ffb05a3fb8f300030811c99ba6830312caf298444f81f4cf1007ddb18aafc86c3b07709355078e76b5c6dc4986f90e3ab4c49eb3277e8f05820000000503099f9f7fc49ca9350ce1951c09325670b8b459f3a55ebe6811f13e10020000000503099f9f7fc49ca9350ce1951c09325670b8b459f3a55ebe6811f13e100fc001108f8192005b687978344fa2433b2aa99d41f643e2d8581a789cdc23084889ceca5244ea82005b687978344fa2433b2aa99d41f643e2d8581a789cdc23084889ceca5244ea80130ade4f9ac0bf7a220bd7931db817cfe4a1948c980bda2b9fa47f388094c433ae05f4ca9336b866f1f0ad1df11d84d9aa40d35322e32342e3132342e313632148feb00404d6f765856c95e587b2523a365bc7258fb4e1ffb05a3fb8f30002012de3ea6678dadb1db529b7fa98762160625055de2aa34e757c93c136233f4a22012de3ea6678dadb1db529b7fa98762160625055de2aa34e757c93c136233f4a20130a0aae269176730e5448cb9f9ad9112e5d8ecf10e7cd60749573096bce1f92a8c54ab971b159b181b2e77d91f03a163420e3231322e32342e3130332e31343914c1161c96de3dae28cd7f20ff8c2aa7b94b866d76fb4e1ffb05a3fb8f300020143dcd6a6b7684fde01e88a10e5d65de9a29244c5ecd586d14a342657025f11320143dcd6a6b7684fde01e88a10e5d65de9a29244c5ecd586d14a342657025f11301308f158752c7ec2792ed365eb5452ffb7284baa0daaccabc0a373fe93e4437ac914e99fa3585ee13b2233ea957a7b875f30d33352e3136342e32332e32343514b5f25f8f70cf8d05c2d2970bdf186c994431d84efb4e1ffb05a3fb8f3000202e48651a2e9c0cb4f2fb7ab874061aa4af0cd28b59695631e6a35af3950ef6fb202e48651a2e9c0cb4f2fb7ab874061aa4af0cd28b59695631e6a35af3950ef6fb0130a61711a34d191e0c70f0f357c9ef6c12f0933031d2d5364ad77f2d2139232bba8450d3dd947923639669dbcb2cdc77000d35342e3134392e33332e313637141ffbf1d32541dcb8f5555305295704a9ff9adc24fb4e1ffb05a3fb8f30002039741ad83dd791e1e738f19edae82d6c0322972e6a455981424da3769b3dbd4a2039741ad83dd791e1e738f19edae82d6c0322972e6a455981424da3769b3dbd4a013095fe0a1e5cec63ada905498014c403049ee0fac572b21ff7d9bfc64e0c58bfc04ec29aa4567fcaf9af431b8925d001e40e33352e3136332e3134342e32333014ec7bf3b9bc72eda38c80bb7cf16e294e763e56b4fb4e1ffb05a3fb8f30002040784f3f9a761c60156f9244a902c0626f8bc8fe003786c70f1fc6be41da467d2040784f3f9a761c60156f9244a902c0626f8bc8fe003786c70f1fc6be41da467d0130b504e0534e88aeb51c3a3f7ca3d6668753ad6502218f173eee918767286822d99f4ee80bf7c07e717d2b107745d63fd70c35322e31302e3232392e3131143e8b10646ee9d6c28d75c280b357dd3a9ae9f962fb4e1ffb05a3fb8f3000205b246080ba64350685fe302d3d790f5bb238cb619920d46230c844f079944a23205b246080ba64350685fe302d3d790f5bb238cb619920d46230c844f079944a230130a16d937e47da149a8c71d34c552c98585faafa99c2986397fc8455e45adf1573dd4535806a8a084b7fa34bbeea9253a80d33352e3136352e35302e31323614f460a07a2b0dc932e1d8ff2dee2b984ac415dcebfb4e1ffb05a3fb8f3000205c6542766615387183715d958a925552472f93335fa1612880423e4bbdaef436205c6542766615387183715d958a925552472f93335fa1612880423e4bbdaef4360130a547a8172171c9ddaeae2eb272e92184a751a53d51476684342c06f6968c32dd9a23742df2e9194613934c5e58ef7e620d34342e3233392e33392e31353314972a33056d57359de8acfa4fb8b29dc1c14f76b8fb4e1ffb05a3fb8f30002061d33f478933797be4de88353c7c2d843c21310f6d00f6eff31424a756ee7dfb2061d33f478933797be4de88353c7c2d843c21310f6d00f6eff31424a756ee7dfb0130a5374524f11f982d5bc082567c60fa9c1bc5be1510eeb42b0f6c2810c8e6da16e609603ce456f17df3636c5407ca5d160c35322e31322e3137362e3930147ada3e486409b39c94a0833c8d782f35bc24e96afb4e1ffb05a3fb8f3000206d1b185ba036efcd44a77e05a9aaf69a0c4e40976aec00b04773e52863320966206d1b185ba036efcd44a77e05a9aaf69a0c4e40976aec00b04773e528633209660130972f1c4070d037808f22be8a28ec2b12a4737a70d803498b39b9c1cd5f060a3c14b8682c484517e66b10f8a339e1f1900e34342e3232382e3234322e31383114c374f016ea61e76aab79b8bb95a1ba0e6e3eee6ffb4e1ffb05a3fb8f3000207135069642e1a72807a383fb5a14b9af6758292fee53fe2a7f7ac6f528bf7019207135069642e1a72807a383fb5a14b9af6758292fee53fe2a7f7ac6f528bf70190130843e716b0c02fff03ab196cf7807890ea4135b104698007370fbaad68eda6926588a2252c8716fbcff2f2e18de92da4e0d35342e3138392e3136342e333914f9956e70daffa263e8cf29fa6557b7b630a595a8fb4e1ffb05a3fb8f300020754b89dae8db20fc4cee5e3adb07b146d7efe508a66fa0a8e1094675b9daa35e20754b89dae8db20fc4cee5e3adb07b146d7efe508a66fa0a8e1094675b9daa35e0130ace190d30463989a24b517945d94dc45894993e493cd32be40bc8b0d0946801af5be6ce4cd0bdf1189436bf085ed96df0c34342e3233332e34342e39351446d938862af6d9a291e26c0048177db2892a710bfb4e1ffb05a3fb8f3000207718edad371e46d20fad30086e4acf4a05c2b660df6ae5f2a684aebdf1be4290207718edad371e46d20fad30086e4acf4a05c2b660df6ae5f2a684aebdf1be429001308a393458f5158095c5b380e1bc1a19ebc9060d6322422bcebf338382de0accb2d24783a33ad9f0bd06f0b522ce9b2dfa0d34342e3232372e3133372e3737140498ade3c80045c2a7520e921180ae1c39da5c57fb4e1ffb05a3fb8f30002085f15a31d3838293a9c1d72a1a0fa21e66110ce20878bd4c1024c4ae1d5be8242085f15a31d3838293a9c1d72a1a0fa21e66110ce20878bd4c1024c4ae1d5be8240130868eea59f1f6748680f0513feec4c06fbc416c3a37a45494fc1a8aab3982c3c0dd206af2d6bdfd28f3f88be4fd3b2f080d35342e3230312e33322e3133311468c506d43816d1a8389c860c1d162be44d1e777cfb4e1ffb05a3fb8f30002087075234ac47353b42bb97ce46330cb67cd4648c01f0b2393d7e729b0d6789182087075234ac47353b42bb97ce46330cb67cd4648c01f0b2393d7e729b0d6789180130862184496a4ed2deea7ad130bca509f8ca0ebda660ab7b5189f3c40e8f3e62c665e0031ccc7bffdc32a5fb921a022e930e33352e3136372e3134352e313439149b9cdbfe3568cc0b37f136b00a634c75653f05e3fb4e1ffb05a3fb8f30002088251bd4b124efeb87537deabeec54f6c8f575f4df81f10cf5e8eea073092b6f2088251bd4b124efeb87537deabeec54f6c8f575f4df81f10cf5e8eea073092b6f013097f08edddfd65e13651bf00b0f3485e2d81a477f45d9b46bdda40a416178cb0fb16199a2f8e969cfb37ed37c234a9cd20b35322e33332e32382e343714711fd9548ae19b2e91c7a9b4067000467ccdd2b5fb4e1ffb05a3fb8f3000208917bb546318f3410d1a7901c7b846a73446311b5164b45a03f0e613f208f234208917bb546318f3410d1a7901c7b846a73446311b5164b45a03f0e613f208f2340130a8e6429fd5e3e981383c03637e707d3b313fbc1606a8023a40e48bf071e45db9b451a3fd2760d28d75a43417e958e7830d35322e31332e3133322e313436145bdbf34a0dad860c6ec71523ae39373325225cc1fb4e1ffb05a3fb8f3000208e11eb784883d3dc9d0d74a74633f067dc61c408dfdee49b8f93bb161f2916c0208e11eb784883d3dc9d0d74a74633f067dc61c408dfdee49b8f93bb161f2916c00130b2fad499c0eced2e83c79ea1c2b03ec399b2fb7411fe2a744979277b75d401b039dbcece4d9d3c0e035c339901d7a6330c35322e38392e3135342e3438146d57707c196e06487d326094c964f258f5b77c35fb4e1ffb05a3fb8f3000208eca4bcbb3a124ab283afd42dad3bdb2077b3809659788a0f1daffce5b9f001f208eca4bcbb3a124ab283afd42dad3bdb2077b3809659788a0f1daffce5b9f001f0130990f8dfc1e064ccb5c1dae252c390fc0ca792e730cada8ca1bd9a0b87a22bd08692827b19e614886125734d25bdbbb1c0d35342e36382e3233352e32303114c075993a8336f93a13bb7bbb7e0e89928be4aafbfb4e1ffb05a3fb8f30002091bbce94c34ebde0d099c0a2cb7635c0c31425ebabcec644f4f1a0854bfa605d2091bbce94c34ebde0d099c0a2cb7635c0c31425ebabcec644f4f1a0854bfa605d013082743c519fc81d9496a0b6b5dea3010daebd5d07e7819fdca3a7b9763c9cc96554f45243e4f3dd3bd550556630ea0e4c0c35322e34302e3231392e34311402aa69f8ef6666e7cad6d9323755a0ef3c1b6bd9fb4e1ffb05a3fb8f3000209cb04f271ba050132c00cc5838fb69e77bc55b5689f9d2d850dc528935f8145c209cb04f271ba050132c00cc5838fb69e77bc55b5689f9d2d850dc528935f8145c0130a87c6b9f8d841bac3ad961c636f6112def93e8f1444da8ed44fb45eb8b8f76c64c4eb56f2d6a4c73bfc7bebbe388bff60c33342e3231342e34382e36381462e960a3f6b650feed98a266b3ccdf6e363562cffb4e1ffb05a3fb8f300020c11c1168dcf9479475cb1355855e30ea75c0cdda8a8f9ea80591568dd1c33ba820c11c1168dcf9479475cb1355855e30ea75c0cdda8a8f9ea80591568dd1c33ba80130821654a83db6fda5da7398f8caf30cec37f572cbb06ab2c16087b5a10f5bc02ecb9b577282b56be8efd15dd743d3a49a0d35342e3231332e3230342e383514fdae7cdf38811659ce9481975b326a5d07236bc5fb4e1ffb05a3fb8f300020d9b090cfc19caf2e27d512e69c43812a274bdf29c081d0ade4fd272ad56a5f8920d9b090cfc19caf2e27d512e69c43812a274bdf29c081d0ade4fd272ad56a5f890130b95ef4d4f00f59a98abefd80d26838fa5e6ebbbf7f53708cea1e4bb5bc29b4db8df9a2b212915bce9c6c9243335695150d34342e3234302e39382e313032147034f0d3853c5351fb8e0ffd3c1daf12c51c2d89fb4e1ffb05a3fb8f300020f6496d3c0ac1ad94ff5e3aab2edcabc1c8ba3fbfea0ef3026e90ba786399038120f6496d3c0ac1ad94ff5e3aab2edcabc1c8ba3fbfea0ef3026e90ba7863990381013082799988066eb079178da860dea57e31e6908b1395b7ff048078d62c21a8c1a8d3356aaedfa3946054ef8803b04d82700d35322e31332e3235302e31383214fe2d4798df3e9b41a6823bc0b3f020478e87925dfb4e1ffb05a3fb8f300020ff261d2c1c76907a2ad8aeb6c5611796f03b5cbd88ae92452a4727e13f4f4ac920ff261d2c1c76907a2ad8aeb6c5611796f03b5cbd88ae92452a4727e13f4f4ac90130b99743b53234d7c72f44f464edf915d5ede43f8864b8c5224c7b2ff1f3d3afe29ee1313bd1d24eb20ea9436fd59d0e5c0d35342e3138372e31342e3233321467e05b1b52c7c896adf20035036fe1d30dcefc9cfb4e1ffb05a3fb8f300030b5da956497c5d4f39fca6f5b1c03f6c05992d1d654f226cf79019376aa64597614dd570190e16958718b9941acd718a1200000004d43bd84ac6be16b9b7e352b3e9905e1337d7d4d6dd0b8a0ff92a89f1c00200000004d43bd84ac6be16b9b7e352b3e9905e1337d7d4d6dd0b8a0ff92a89f1c00fc001108e01920143dcd6a6b7684fde01e88a10e5d65de9a29244c5ecd586d14a342657025f11320143dcd6a6b7684fde01e88a10e5d65de9a29244c5ecd586d14a342657025f11301308b460fcb3cc7ee796175caa6f052d3bdc69e818d74112b2ab846c918669bf638c7ee40ed205995a29033acc18d59ddb80d33352e3136342e32332e32343514b5f25f8f70cf8d05c2d2970bdf186c994431d84efb4e1ffb05a3fb8f30002020107ec50e81880dca18178bb7e53e2d0449c0734106a607253b9af2ffea006c2020107ec50e81880dca18178bb7e53e2d0449c0734106a607253b9af2ffea006c0130ae54bad16d671bc5c15961a2831600a97d2d45656a05d3ff23e1dfbca7b7ffaf3f6849b963d7c6da2207bc45f82149180c33352e38352e32312e3137391435d9eb76397d05b43b5cd8da7ccfa8408bc89ab3fb4e1ffb05a3fb8f30002039741ad83dd791e1e738f19edae82d6c0322972e6a455981424da3769b3dbd4a2039741ad83dd791e1e738f19edae82d6c0322972e6a455981424da3769b3dbd4a0130a754aef784851c7b33edc0672fdc4acbbb5b68d18cc599d5ea0f90dc18f1d0f9b240852300bb4897a840c3ad75ad92720e33352e3136332e3134342e32333014ec7bf3b9bc72eda38c80bb7cf16e294e763e56b4fb4e1ffb05a3fb8f30002040784f3f9a761c60156f9244a902c0626f8bc8fe003786c70f1fc6be41da467d2040784f3f9a761c60156f9244a902c0626f8bc8fe003786c70f1fc6be41da467d0130997667cb4a12ed8a163f798d3adb2ce58fd6893a43f6076aaa4361fb72252e0b199e4ec1ce8a5f7c28cd4569f22811760c35322e31302e3232392e3131143e8b10646ee9d6c28d75c280b357dd3a9ae9f962fb4e1ffb05a3fb8f3000205b246080ba64350685fe302d3d790f5bb238cb619920d46230c844f079944a23205b246080ba64350685fe302d3d790f5bb238cb619920d46230c844f079944a2301308f7f1b73f23c47a901bc0fcafee3390f1814082c6ba58fbe8ff3bfb2d8ae59e166b9bf4cafeb73ab84f8c92bf025d5680d33352e3136352e35302e31323614f460a07a2b0dc932e1d8ff2dee2b984ac415dcebfb4e1ffb05a3fb8f30002061d33f478933797be4de88353c7c2d843c21310f6d00f6eff31424a756ee7dfb2061d33f478933797be4de88353c7c2d843c21310f6d00f6eff31424a756ee7dfb0130af907e5db8f2044c7439fcf769805a1cb6d6fe054dcc0143f1fc016887fa3e5d118d00ee3915a17232d4d3399fe72d5b0c35322e31322e3137362e3930147ada3e486409b39c94a0833c8d782f35bc24e96afb4e1ffb05a3fb8f3000206d1b185ba036efcd44a77e05a9aaf69a0c4e40976aec00b04773e52863320966206d1b185ba036efcd44a77e05a9aaf69a0c4e40976aec00b04773e528633209660130a09832716c65b1546e347932ef900e805a201ce2dcc0f63f9a4134f0f63e1f1a8fe21c73c8bb611f8be20e39534e083c0e34342e3232382e3234322e31383114c374f016ea61e76aab79b8bb95a1ba0e6e3eee6ffb4e1ffb05a3fb8f3000207135069642e1a72807a383fb5a14b9af6758292fee53fe2a7f7ac6f528bf7019207135069642e1a72807a383fb5a14b9af6758292fee53fe2a7f7ac6f528bf70190130b08d9d26e9e4be1c5126efd8ddb59794fd773a02842acc3d3da4bac6c0c617e6d7252eb8b6cf39c31768046f428d2ce20d35342e3138392e3136342e333914f9956e70daffa263e8cf29fa6557b7b630a595a8fb4e1ffb05a3fb8f300020754b89dae8db20fc4cee5e3adb07b146d7efe508a66fa0a8e1094675b9daa35e20754b89dae8db20fc4cee5e3adb07b146d7efe508a66fa0a8e1094675b9daa35e013097532b6be5b41d239a8645d8d64afb5cef699c098a67b4a9937821bc1dd20b5bdee4c1e426c5a7f8052eb3952190cfa70c34342e3233332e34342e39351446d938862af6d9a291e26c0048177db2892a710bfb4e1ffb05a3fb8f3000207718edad371e46d20fad30086e4acf4a05c2b660df6ae5f2a684aebdf1be4290207718edad371e46d20fad30086e4acf4a05c2b660df6ae5f2a684aebdf1be42900130ab556ce9c2e2700225559ec1959d45c83253cb296dce2b6b33cbfe9b874dbfe9dbe904fa2dcea902415fc1ecfc39474a0d34342e3232372e3133372e3737140498ade3c80045c2a7520e921180ae1c39da5c57fb4e1ffb05a3fb8f30002085f15a31d3838293a9c1d72a1a0fa21e66110ce20878bd4c1024c4ae1d5be8242085f15a31d3838293a9c1d72a1a0fa21e66110ce20878bd4c1024c4ae1d5be8240130b54b2015b5e21346dbc940cc84bf51b4e6ff48dde45eee42fda6fd2e52ecb69a3a59583d4f07abcb116277878de85d590d35342e3230312e33322e3133311468c506d43816d1a8389c860c1d162be44d1e777cfb4e1ffb05a3fb8f30002087075234ac47353b42bb97ce46330cb67cd4648c01f0b2393d7e729b0d6789182087075234ac47353b42bb97ce46330cb67cd4648c01f0b2393d7e729b0d6789180130b07b9e19df45bab4886e1725af1ceb51c9ec8d6b7de345396996a5d541f0360fde8b4cd19e09c01fb82bf36460c9ce060e33352e3136372e3134352e313439149b9cdbfe3568cc0b37f136b00a634c75653f05e3fb4e1ffb05a3fb8f3000208b8d1193afd22e538ce0c9fb50fee155d0f6176ca68e65da684c5dce2d1e0815208b8d1193afd22e538ce0c9fb50fee155d0f6176ca68e65da684c5dce2d1e08150130a2578e7fa88cdd15a5eaf6f627d5180fb2c5867b1a63435e6cc69087b219012d39fdd00bed9c975a4692ef5b55212ba20c35322e33342e3134342e353014a0a0e17bfe82a484fefe348b7569a6d77d29d2c2fb4e1ffb05a3fb8f3000208de8b12952f7058d827bd04cdff1c2175d87bbf89f28b52452a637bc979addc4208de8b12952f7058d827bd04cdff1c2175d87bbf89f28b52452a637bc979addc4013088f04eb6df9fd7339e63ceb4eebc70de145b4013dd6df67e22de136983e4065a5afe874be3352522a801c2c20a7f90cd0c35322e34332e38362e32333114337b7fb5d2c531825c3e0123ac3354018085b302fb4e1ffb05a3fb8f3000208e11eb784883d3dc9d0d74a74633f067dc61c408dfdee49b8f93bb161f2916c0208e11eb784883d3dc9d0d74a74633f067dc61c408dfdee49b8f93bb161f2916c0013089ef74e90f14b3548986e55bf793a404f6c6c51d37ac118fe09f8869c71fd25aeba2f6c6951cf41fd5ca240907a760690c35322e38392e3135342e3438146d57707c196e06487d326094c964f258f5b77c35fb4e1ffb05a3fb8f3000208eca4bcbb3a124ab283afd42dad3bdb2077b3809659788a0f1daffce5b9f001f208eca4bcbb3a124ab283afd42dad3bdb2077b3809659788a0f1daffce5b9f001f01309796d4499f58876deedf4904e96de7c6f308aea15e7f1495db988e1dd70c5703fc3338127dd6fbaa638fd09d9a2495440d35342e36382e3233352e32303114c075993a8336f93a13bb7bbb7e0e89928be4aafbfb4e1ffb05a3fb8f30002091bbce94c34ebde0d099c0a2cb7635c0c31425ebabcec644f4f1a0854bfa605d2091bbce94c34ebde0d099c0a2cb7635c0c31425ebabcec644f4f1a0854bfa605d0130a28553f210bcac6400cfae3cf36294b373acdd4d66b92bd30c0c7230f5cc080e6546eb961f6432e51e0d88d1449185f70c35322e34302e3231392e34311402aa69f8ef6666e7cad6d9323755a0ef3c1b6bd9fb4e1ffb05a3fb8f3000209712e85d660fa2f761f980ef5812c225f33f336f285728803dcd421937d3df54209712e85d660fa2f761f980ef5812c225f33f336f285728803dcd421937d3df540130a04038f4955841d76aae11e2c4b51c4efbf4bbc4c5af0a6132d9d8d5134ea141ed2e791cff5056981015b9eb03f96d790d33352e38322e3139372e31393714ed1131823bcea23ac78af8c01e4d24683d6ecf88fb4e1ffb05a3fb8f30002098ef58c338a0a68e4f2f1d1ee9eb05fcafbb9177d192dac0f698d3d9ba0920962098ef58c338a0a68e4f2f1d1ee9eb05fcafbb9177d192dac0f698d3d9ba0920960130a883d1e8398a8cf66ff2c695422b1caaaa7df58efc0637b38b48621c2e3357d25618b6e54335a311fba33c1a60fa8c540c34342e3233322e3139362e3614d6ece912cbf02627a4efc3dd37e6833cf3671551fb4e1ffb05a3fb8f3000209cb04f271ba050132c00cc5838fb69e77bc55b5689f9d2d850dc528935f8145c209cb04f271ba050132c00cc5838fb69e77bc55b5689f9d2d850dc528935f8145c0130aab78e91fd352d70ed1c717c4d69726dc6cfeba4c6047040fb52cb0b6eb06aacba7c11e780f17e29da8886d5207d7d2d0c33342e3231342e34382e36381462e960a3f6b650feed98a266b3ccdf6e363562cffb4e1ffb05a3fb8f300020b3b5748571b60fe9ad112715d6a51725d6e5a52a9c3af5fd36a1724cf50d862f20b3b5748571b60fe9ad112715d6a51725d6e5a52a9c3af5fd36a1724cf50d862f013092d3231b5c4ca6ad3957123950f519f38d5a03a65161eadfddbe218afc12a9845ada84209325149769949c8870a25d4a0b35322e34332e31332e39321441b308f737ca9e39f67b553158903198a88c516efb4e1ffb05a3fb8f300020ba8ce1dc72857b4168e33272571df7fbaf84c316dfe48217addcf6595e25421620ba8ce1dc72857b4168e33272571df7fbaf84c316dfe48217addcf6595e254216013083f05b849c08d76c2b699210c780112ef7ee1d76ae57cb216afc4a0a97ebe696e723f4c0f885a5329c8efd2727ee9f9f0d35322e34322e3230322e3132381462e0104ce0aafc1f06bde37c73702fe84b307f05fb4e1ffb05a3fb8f300020bbfd0ac1977011267a7032641ef5487fe15a4de798faa485b156fb3b7eb0acb820bbfd0ac1977011267a7032641ef5487fe15a4de798faa485b156fb3b7eb0acb8013086283e5e604d24192e21ce9a909afbc49045776ee5145aeccdedd7b52e4a0ebb184ca3c9d837f2d4d6a1b0e91104fd2b0c33352e38322e34392e31393614dbbebbc52a5bae21b818e0487311041c91b2683bfb4e1ffb05a3fb8f300020c11c1168dcf9479475cb1355855e30ea75c0cdda8a8f9ea80591568dd1c33ba820c11c1168dcf9479475cb1355855e30ea75c0cdda8a8f9ea80591568dd1c33ba801308c9d01a4115483815958f4a125dfbf62d7ec434070e27d4aa68900709d9e6c178b1d4109fc9b6de2c7485cfc0e8597f30d35342e3231332e3230342e383514fdae7cdf38811659ce9481975b326a5d07236bc5fb4e1ffb05a3fb8f300020d9b090cfc19caf2e27d512e69c43812a274bdf29c081d0ade4fd272ad56a5f8920d9b090cfc19caf2e27d512e69c43812a274bdf29c081d0ade4fd272ad56a5f890130a4ed1dc172bcaed49303cf1fc09c8b7307cd3a6ce73813c7ad4771f165e11c091a5f6b89f1faaca3596e70dd23a81cdd0d34342e3234302e39382e313032147034f0d3853c5351fb8e0ffd3c1daf12c51c2d89fb4e1ffb05a3fb8f30003094c59ea9aec7e4e60572a74af7ccb95127fb165f09adc32178ad80e4bc58f63161d9f02833a9980c23db78640cd67e8320000000d4b6e3c3b706bd8941885c8fb46dee63ffbe116888d8892b7f53a0a0da0020000000d4b6e3c3b706bd8941885c8fb46dee63ffbe116888d8892b7f53a0a0da00fc001108c8192005b687978344fa2433b2aa99d41f643e2d8581a789cdc23084889ceca5244ea82005b687978344fa2433b2aa99d41f643e2d8581a789cdc23084889ceca5244ea80130a05b8b13fdcc6917524714eb250387f6330775cb97dbc6724a73246a480c1504469a777d03478de1d3bb535baeef5c7f0d35322e32342e3132342e313632148feb00404d6f765856c95e587b2523a365bc7258fb4e1ffb05a3fb8f30002012de3ea6678dadb1db529b7fa98762160625055de2aa34e757c93c136233f4a22012de3ea6678dadb1db529b7fa98762160625055de2aa34e757c93c136233f4a20130a726d33bb1b575eef918031911618076c72b24b7c00e0f093feb2c2f14d1fd83d3ef4e4351d329afa693264644dd220c0e3231322e32342e3130332e31343914c1161c96de3dae28cd7f20ff8c2aa7b94b866d76fb4e1ffb05a3fb8f300020143dcd6a6b7684fde01e88a10e5d65de9a29244c5ecd586d14a342657025f11320143dcd6a6b7684fde01e88a10e5d65de9a29244c5ecd586d14a342657025f1130130af03210533c4b3b2200dbc65961590904b19e8132fc759c0bd6ab38c88078ce9f1ded55e4c46e8f000f5744e5927fcd80d33352e3136342e32332e32343514b5f25f8f70cf8d05c2d2970bdf186c994431d84efb4e1ffb05a3fb8f30002020107ec50e81880dca18178bb7e53e2d0449c0734106a607253b9af2ffea006c2020107ec50e81880dca18178bb7e53e2d0449c0734106a607253b9af2ffea006c0130a7740f3302e48e88527030630d7c776cd4f0738a0413fa26b1acd1053e24eb42aad8c606f24b226fdae48a25db7b62d00c33352e38352e32312e3137391435d9eb76397d05b43b5cd8da7ccfa8408bc89ab3fb4e1ffb05a3fb8f3000202e48651a2e9c0cb4f2fb7ab874061aa4af0cd28b59695631e6a35af3950ef6fb202e48651a2e9c0cb4f2fb7ab874061aa4af0cd28b59695631e6a35af3950ef6fb0130967b38cebd11a41fc82acb6739a375e5459c51804ed58be7e7eb384481dc6631ebb32ad78ed5c21624ea6af1202ef03a0d35342e3134392e33332e313637141ffbf1d32541dcb8f5555305295704a9ff9adc24fb4e1ffb05a3fb8f30002039741ad83dd791e1e738f19edae82d6c0322972e6a455981424da3769b3dbd4a2039741ad83dd791e1e738f19edae82d6c0322972e6a455981424da3769b3dbd4a01308b5e034afabfc19434e05306ed05e611efba5eb2b6e199114266d60f315a9d3aba5e913d20dd060478d58667cda4c6290e33352e3136332e3134342e32333014ec7bf3b9bc72eda38c80bb7cf16e294e763e56b4fb4e1ffb05a3fb8f30002040784f3f9a761c60156f9244a902c0626f8bc8fe003786c70f1fc6be41da467d2040784f3f9a761c60156f9244a902c0626f8bc8fe003786c70f1fc6be41da467d01309398faf325dbac5f84b53d53dc0118e187ef1cfab954a1f41e5474d893e779fad2cf9206df0f28ba31938a07543ae1c00c35322e31302e3232392e3131143e8b10646ee9d6c28d75c280b357dd3a9ae9f962fb4e1ffb05a3fb8f3000205b246080ba64350685fe302d3d790f5bb238cb619920d46230c844f079944a23205b246080ba64350685fe302d3d790f5bb238cb619920d46230c844f079944a230130abc8583618c7a847a00a0d2164a28ebdcead0d7a23df00553f9e0fdca2a8049f0504d9a4d472131e671de8fc1d4e99960d33352e3136352e35302e31323614f460a07a2b0dc932e1d8ff2dee2b984ac415dcebfb4e1ffb05a3fb8f3000205c6542766615387183715d958a925552472f93335fa1612880423e4bbdaef436205c6542766615387183715d958a925552472f93335fa1612880423e4bbdaef4360130a6d31c009e09302a3d19f5dd1c56ad3e8b9205a1a23c49e93721599d6623be423bf85f72aa3ada53bcbfe0d9da1a93fc0d34342e3233392e33392e31353314972a33056d57359de8acfa4fb8b29dc1c14f76b8fb4e1ffb05a3fb8f30002061d33f478933797be4de88353c7c2d843c21310f6d00f6eff31424a756ee7dfb2061d33f478933797be4de88353c7c2d843c21310f6d00f6eff31424a756ee7dfb0130a0ff36d3273675e24d02d0f3e4083f99388b3561333abbeea8a46ad84e06e536f595382ca44aefc370ca7d64ef88b5b90c35322e31322e3137362e3930147ada3e486409b39c94a0833c8d782f35bc24e96afb4e1ffb05a3fb8f300020754b89dae8db20fc4cee5e3adb07b146d7efe508a66fa0a8e1094675b9daa35e20754b89dae8db20fc4cee5e3adb07b146d7efe508a66fa0a8e1094675b9daa35e0130b56355b74fbe62ca05d14bdf3d1896465cd5b41e897da999c08ad39e7a4fafe32c46fee3536dce92db32347a0fcebc5e0c34342e3233332e34342e39351446d938862af6d9a291e26c0048177db2892a710bfb4e1ffb05a3fb8f30002085f15a31d3838293a9c1d72a1a0fa21e66110ce20878bd4c1024c4ae1d5be8242085f15a31d3838293a9c1d72a1a0fa21e66110ce20878bd4c1024c4ae1d5be8240130ae8ea031f0c46ea23fe6c45199e9e089283dd1003d6eeac30541b20b45989756052e943853f83e015e7060fdffae94c80d35342e3230312e33322e3133311468c506d43816d1a8389c860c1d162be44d1e777cfb4e1ffb05a3fb8f30002087075234ac47353b42bb97ce46330cb67cd4648c01f0b2393d7e729b0d6789182087075234ac47353b42bb97ce46330cb67cd4648c01f0b2393d7e729b0d678918013088c024a804b1cd694b087c8648789fbb3b4653784a1bbfab88db8afc2c8fb87cfdff5aed6eb6561d301e4cff2336c9060e33352e3136372e3134352e313439149b9cdbfe3568cc0b37f136b00a634c75653f05e3fb4e1ffb05a3fb8f30002088251bd4b124efeb87537deabeec54f6c8f575f4df81f10cf5e8eea073092b6f2088251bd4b124efeb87537deabeec54f6c8f575f4df81f10cf5e8eea073092b6f013093aae6cf15f02ce0939bad8f654d85a724c70b8bbffeccb336bcdf7cae780057ed4e579d25511d3dc8c79700f7902c8a0b35322e33332e32382e343714711fd9548ae19b2e91c7a9b4067000467ccdd2b5fb4e1ffb05a3fb8f3000208917bb546318f3410d1a7901c7b846a73446311b5164b45a03f0e613f208f234208917bb546318f3410d1a7901c7b846a73446311b5164b45a03f0e613f208f23401308596fa5844b472ff7e62d6a083c2c37dbced2d8279d617392f79329539a30606f24f072a6f89119f8580c031867c97750d35322e31332e3133322e313436145bdbf34a0dad860c6ec71523ae39373325225cc1fb4e1ffb05a3fb8f3000208b8d1193afd22e538ce0c9fb50fee155d0f6176ca68e65da684c5dce2d1e0815208b8d1193afd22e538ce0c9fb50fee155d0f6176ca68e65da684c5dce2d1e0815013095e700df712726032efacc015206cc8905c6a262d2a09f39c0c4947186778dad1c7e7c0bbd994a828ebf7381297e5a090c35322e33342e3134342e353014a0a0e17bfe82a484fefe348b7569a6d77d29d2c2fb4e1ffb05a3fb8f3000208de8b12952f7058d827bd04cdff1c2175d87bbf89f28b52452a637bc979addc4208de8b12952f7058d827bd04cdff1c2175d87bbf89f28b52452a637bc979addc40130acc4a68d6a4a1a02f015c149e62943d6e2d03699bba71092bb324abdc68a78cd05d28f570ed6517edb456a38cbc20b860c35322e34332e38362e32333114337b7fb5d2c531825c3e0123ac3354018085b302fb4e1ffb05a3fb8f30002091bbce94c34ebde0d099c0a2cb7635c0c31425ebabcec644f4f1a0854bfa605d2091bbce94c34ebde0d099c0a2cb7635c0c31425ebabcec644f4f1a0854bfa605d0130a95f3700cbeb45904f7c09df31e142193aa9b277ec80da5458136a0b4c4c1bf26eb9b8f420b788779d2d92a5db71a4360c35322e34302e3231392e34311402aa69f8ef6666e7cad6d9323755a0ef3c1b6bd9fb4e1ffb05a3fb8f3000209712e85d660fa2f761f980ef5812c225f33f336f285728803dcd421937d3df54209712e85d660fa2f761f980ef5812c225f33f336f285728803dcd421937d3df540130944d564c8f03423d7923069004a0ff33a9febb61295158fb95ada04745f8070410e4f22041d6c5ab1227c8ca7ec5d2b00d33352e38322e3139372e31393714ed1131823bcea23ac78af8c01e4d24683d6ecf88fb4e1ffb05a3fb8f30002098ef58c338a0a68e4f2f1d1ee9eb05fcafbb9177d192dac0f698d3d9ba0920962098ef58c338a0a68e4f2f1d1ee9eb05fcafbb9177d192dac0f698d3d9ba09209601308b6c3bd1b6d10f712dcdc043287608210e64357e44076bae3f630063f27a00134479b06655305d4dfc14d783c610ef190c34342e3233322e3139362e3614d6ece912cbf02627a4efc3dd37e6833cf3671551fb4e1ffb05a3fb8f300020ba8ce1dc72857b4168e33272571df7fbaf84c316dfe48217addcf6595e25421620ba8ce1dc72857b4168e33272571df7fbaf84c316dfe48217addcf6595e2542160130a4545d995258e0c25eaa5395cdd85aba924c7653248c79e9b6d54c5c95457f9c383aec10e9c7135910efc896a552cb400d35322e34322e3230322e3132381462e0104ce0aafc1f06bde37c73702fe84b307f05fb4e1ffb05a3fb8f300020bbfd0ac1977011267a7032641ef5487fe15a4de798faa485b156fb3b7eb0acb820bbfd0ac1977011267a7032641ef5487fe15a4de798faa485b156fb3b7eb0acb80130a963c8918e33ab77885122c7e72dc5d5ed58747b6341d055c36af803af19b674eaacfa397368cfe31e50e0458663a7700c33352e38322e34392e31393614dbbebbc52a5bae21b818e0487311041c91b2683bfb4e1ffb05a3fb8f300020c11c1168dcf9479475cb1355855e30ea75c0cdda8a8f9ea80591568dd1c33ba820c11c1168dcf9479475cb1355855e30ea75c0cdda8a8f9ea80591568dd1c33ba80130b09a36c2cd9523f2036fe71755ce02b4722467eabbe2d9606ddcaf5c1c73f8dd21c1d697c9bece75d952f13adac2b9670d35342e3231332e3230342e383514fdae7cdf38811659ce9481975b326a5d07236bc5fb4e1ffb05a3fb8f300020d9b090cfc19caf2e27d512e69c43812a274bdf29c081d0ade4fd272ad56a5f8920d9b090cfc19caf2e27d512e69c43812a274bdf29c081d0ade4fd272ad56a5f890130a0f49df8abdbc389ab1bbb99ca45a4268d7858301b259652dfc699795db7f35113f2d29f4c41cd0029faa88df14c549d0d34342e3234302e39382e313032147034f0d3853c5351fb8e0ffd3c1daf12c51c2d89fb4e1ffb05a3fb8f300020ff261d2c1c76907a2ad8aeb6c5611796f03b5cbd88ae92452a4727e13f4f4ac920ff261d2c1c76907a2ad8aeb6c5611796f03b5cbd88ae92452a4727e13f4f4ac90130864a2eb7c4019522c831b28bb8c84ec256556f06d90e71f05d12cebd6cc3e8a9360749637e9f7acd2c8bf08d438eaead0d35342e3138372e31342e3233321467e05b1b52c7c896adf20035036fe1d30dcefc9cfb4e1ffb05a3fb8f300030a89b8a9e053bcedea6d6c29e63526edf069639d25ec8ceb1f6f127e3259c71769f1e54d867ca5b8449c8d55c19248cd720000000ceb90097be7a897c47be4752340dab3c394e860cac4f03f7bce60caa860020000000ceb90097be7a897c47be4752340dab3c394e860cac4f03f7bce60caa8600fc001108b0192012de3ea6678dadb1db529b7fa98762160625055de2aa34e757c93c136233f4a22012de3ea6678dadb1db529b7fa98762160625055de2aa34e757c93c136233f4a2013088a4d69c5ae7263da2494237b4eb77db4cc5e59d3a3f1413a35c96684b858db2be1f22203712c93a51befaf591bd972c0e3231322e32342e3130332e31343914c1161c96de3dae28cd7f20ff8c2aa7b94b866d76fb4e1ffb05a3fb8f30002020107ec50e81880dca18178bb7e53e2d0449c0734106a607253b9af2ffea006c2020107ec50e81880dca18178bb7e53e2d0449c0734106a607253b9af2ffea006c0130aebaa7d29121c7845ae2aa701eea659f2d54c0151eabaf7f2069ffed57a846deb657e6376f5f5f6aed9c3060e2ffeb030c33352e38352e32312e3137391435d9eb76397d05b43b5cd8da7ccfa8408bc89ab3fb4e1ffb05a3fb8f3000202e48651a2e9c0cb4f2fb7ab874061aa4af0cd28b59695631e6a35af3950ef6fb202e48651a2e9c0cb4f2fb7ab874061aa4af0cd28b59695631e6a35af3950ef6fb01308e081ac0afd47eb31e2e796c69a3cba48c4a7f5c63b71ff5ad946c6b193bd0c921fe3ae922eb0e8d5c6123907ca66ba60d35342e3134392e33332e313637141ffbf1d32541dcb8f5555305295704a9ff9adc24fb4e1ffb05a3fb8f3000205b246080ba64350685fe302d3d790f5bb238cb619920d46230c844f079944a23205b246080ba64350685fe302d3d790f5bb238cb619920d46230c844f079944a230130a1814ef35a03c54d6ea3170d794a4dd10bd6d49aea8fe03d1607a240c94083dceb3a69e1dad6ec2f3f49f818b9ee462a0d33352e3136352e35302e31323614f460a07a2b0dc932e1d8ff2dee2b984ac415dcebfb4e1ffb05a3fb8f3000205c6542766615387183715d958a925552472f93335fa1612880423e4bbdaef436205c6542766615387183715d958a925552472f93335fa1612880423e4bbdaef4360130a71ce89bb92a4730672b2c774de958dd4c85dc53461cb41105d7766aabe1b473722a483585603c3323e2bf7bfb3d47e90d34342e3233392e33392e31353314972a33056d57359de8acfa4fb8b29dc1c14f76b8fb4e1ffb05a3fb8f3000206d1b185ba036efcd44a77e05a9aaf69a0c4e40976aec00b04773e52863320966206d1b185ba036efcd44a77e05a9aaf69a0c4e40976aec00b04773e52863320966013093bec6a7ba821198140ab7a1d0ea93a96d8a2b961f7a09b594ec768b0e99bbb74e8ef075efc43943f7f4d2c73d967ed00e34342e3232382e3234322e31383114c374f016ea61e76aab79b8bb95a1ba0e6e3eee6ffb4e1ffb05a3fb8f3000207135069642e1a72807a383fb5a14b9af6758292fee53fe2a7f7ac6f528bf7019207135069642e1a72807a383fb5a14b9af6758292fee53fe2a7f7ac6f528bf70190130b8de15f05a0fa8b4606fc7aa14fef15c5c9ac74b8b8de56761fd870c40d1fe9f0a1e0e75fd05ce23989acd3002aa54100d35342e3138392e3136342e333914f9956e70daffa263e8cf29fa6557b7b630a595a8fb4e1ffb05a3fb8f3000207718edad371e46d20fad30086e4acf4a05c2b660df6ae5f2a684aebdf1be4290207718edad371e46d20fad30086e4acf4a05c2b660df6ae5f2a684aebdf1be429001308cc7fc20d72fbad37344f1f22fd028878f9eb1ce487464d8bb7e88511703289b03f636cbe329bc724d1fd7a5e0e228950d34342e3232372e3133372e3737140498ade3c80045c2a7520e921180ae1c39da5c57fb4e1ffb05a3fb8f30002085f15a31d3838293a9c1d72a1a0fa21e66110ce20878bd4c1024c4ae1d5be8242085f15a31d3838293a9c1d72a1a0fa21e66110ce20878bd4c1024c4ae1d5be8240130826005c487974a10dfc6c0e9b81d36d01f7868f28cd41bcbf1c70ea40085d054e1c466f7e3481fed2c051bcf3f2e8ffb0d35342e3230312e33322e3133311468c506d43816d1a8389c860c1d162be44d1e777cfb4e1ffb05a3fb8f30002087075234ac47353b42bb97ce46330cb67cd4648c01f0b2393d7e729b0d6789182087075234ac47353b42bb97ce46330cb67cd4648c01f0b2393d7e729b0d6789180130ab28bc9b23df49c4dab9d8ed5dce583172aa6115c64f4799b640337b8f789d1776e8dd2a54fef6cb688421f4f4405f540e33352e3136372e3134352e313439149b9cdbfe3568cc0b37f136b00a634c75653f05e3fb4e1ffb05a3fb8f30002088251bd4b124efeb87537deabeec54f6c8f575f4df81f10cf5e8eea073092b6f2088251bd4b124efeb87537deabeec54f6c8f575f4df81f10cf5e8eea073092b6f0130a69dd93e9acc2df9091efdbb6af018914c02610ecba8f9a87d0072bcb905e69f2f86ef5b0a9db53fe9e0468ea8b47bf10b35322e33332e32382e343714711fd9548ae19b2e91c7a9b4067000467ccdd2b5fb4e1ffb05a3fb8f3000208917bb546318f3410d1a7901c7b846a73446311b5164b45a03f0e613f208f234208917bb546318f3410d1a7901c7b846a73446311b5164b45a03f0e613f208f2340130a28b26c15833231fb3e4f819803c6c197c9ca4666d6bae08c684ec87d36f087d3f7311db12c1d316aa48807a38389af70d35322e31332e3133322e313436145bdbf34a0dad860c6ec71523ae39373325225cc1fb4e1ffb05a3fb8f3000208de8b12952f7058d827bd04cdff1c2175d87bbf89f28b52452a637bc979addc4208de8b12952f7058d827bd04cdff1c2175d87bbf89f28b52452a637bc979addc401309576536e85632411c5464c48458c59388447399d11717b8fb9bd08654efaf40d2c4263574eee84333c569a01186f3cbe0c35322e34332e38362e32333114337b7fb5d2c531825c3e0123ac3354018085b302fb4e1ffb05a3fb8f3000208e11eb784883d3dc9d0d74a74633f067dc61c408dfdee49b8f93bb161f2916c0208e11eb784883d3dc9d0d74a74633f067dc61c408dfdee49b8f93bb161f2916c001308b16d7e9c9d09f4c1c68a485a842c42df657993e39852ecf497a343e2e4091244d6c54426765ed3b35fa5428c56c42060c35322e38392e3135342e3438146d57707c196e06487d326094c964f258f5b77c35fb4e1ffb05a3fb8f3000208eca4bcbb3a124ab283afd42dad3bdb2077b3809659788a0f1daffce5b9f001f208eca4bcbb3a124ab283afd42dad3bdb2077b3809659788a0f1daffce5b9f001f0130a723e5361a30fa8b8abe2ada16f6355bef4426fa666248b1e7acc1166b9c771327a26d8476219366264af23d3690c6850d35342e36382e3233352e32303114c075993a8336f93a13bb7bbb7e0e89928be4aafbfb4e1ffb05a3fb8f30002091bbce94c34ebde0d099c0a2cb7635c0c31425ebabcec644f4f1a0854bfa605d2091bbce94c34ebde0d099c0a2cb7635c0c31425ebabcec644f4f1a0854bfa605d0130a0c9d56c59553573bfd2820e100c32677a0f8acef152aec3a9ba26de65f5c00111e607f84f06054fd9715d53467923a60c35322e34302e3231392e34311402aa69f8ef6666e7cad6d9323755a0ef3c1b6bd9fb4e1ffb05a3fb8f3000209712e85d660fa2f761f980ef5812c225f33f336f285728803dcd421937d3df54209712e85d660fa2f761f980ef5812c225f33f336f285728803dcd421937d3df540130b7da304a882b4b043fb3c9f4b3f1a95b712348df94041029612a987e91eb902dcd12b287747776fec40ca8920df8fe5f0d33352e38322e3139372e31393714ed1131823bcea23ac78af8c01e4d24683d6ecf88fb4e1ffb05a3fb8f30002098ef58c338a0a68e4f2f1d1ee9eb05fcafbb9177d192dac0f698d3d9ba0920962098ef58c338a0a68e4f2f1d1ee9eb05fcafbb9177d192dac0f698d3d9ba0920960130ad516ec8101f2b352444645838f496ef4d3d692cc4f7058175c3dae158625f3a735d78da982faab68d89909392595ddd0c34342e3233322e3139362e3614d6ece912cbf02627a4efc3dd37e6833cf3671551fb4e1ffb05a3fb8f3000209cb04f271ba050132c00cc5838fb69e77bc55b5689f9d2d850dc528935f8145c209cb04f271ba050132c00cc5838fb69e77bc55b5689f9d2d850dc528935f8145c0130adf3ec0568e65c42c340b3dbc03145486abb34af601372b30a992aa66ca5800247e4e3df8c14a74933e7dcbb25f271dd0c33342e3231342e34382e36381462e960a3f6b650feed98a266b3ccdf6e363562cffb4e1ffb05a3fb8f300020b3b5748571b60fe9ad112715d6a51725d6e5a52a9c3af5fd36a1724cf50d862f20b3b5748571b60fe9ad112715d6a51725d6e5a52a9c3af5fd36a1724cf50d862f0130982d001eb233cd0e83f9112eb853945033cee76decb4618ee280bf6125fd082c179639ad92154990877e9d63a55637400b35322e34332e31332e39321441b308f737ca9e39f67b553158903198a88c516efb4e1ffb05a3fb8f300020ba8ce1dc72857b4168e33272571df7fbaf84c316dfe48217addcf6595e25421620ba8ce1dc72857b4168e33272571df7fbaf84c316dfe48217addcf6595e254216013090980e5b0b2050070d1217dbd9694f7c58f00f67827613c3b045897c7fbbdd18e30a9068fb0dff2b73c76946f979ab1c0d35322e34322e3230322e3132381462e0104ce0aafc1f06bde37c73702fe84b307f05fb4e1ffb05a3fb8f300020bbfd0ac1977011267a7032641ef5487fe15a4de798faa485b156fb3b7eb0acb820bbfd0ac1977011267a7032641ef5487fe15a4de798faa485b156fb3b7eb0acb80130ad04595d1ecbded5cc553eca173eea397c402aab1fc08eb46e38013ebb7a4f859fe1f2b32d922bab2fd628d38b9f541f0c33352e38322e34392e31393614dbbebbc52a5bae21b818e0487311041c91b2683bfb4e1ffb05a3fb8f300020d9b090cfc19caf2e27d512e69c43812a274bdf29c081d0ade4fd272ad56a5f8920d9b090cfc19caf2e27d512e69c43812a274bdf29c081d0ade4fd272ad56a5f8901308478b47312f9b93e9d7fc2262c286b0ff0f14edc2fab154c5b6739f849d9257a5c767c06db8e9d27ffec3084ab645fcf0d34342e3234302e39382e313032147034f0d3853c5351fb8e0ffd3c1daf12c51c2d89fb4e1ffb05a3fb8f300020f6496d3c0ac1ad94ff5e3aab2edcabc1c8ba3fbfea0ef3026e90ba786399038120f6496d3c0ac1ad94ff5e3aab2edcabc1c8ba3fbfea0ef3026e90ba7863990381013082e166338742861b258ef7ba49636a4f1b0febeb9a19216c758465c4e6d0822ed3f7887e9f474ed474ffad65d86496ee0d35322e31332e3235302e31383214fe2d4798df3e9b41a6823bc0b3f020478e87925dfb4e1ffb05a3fb8f300020ff261d2c1c76907a2ad8aeb6c5611796f03b5cbd88ae92452a4727e13f4f4ac920ff261d2c1c76907a2ad8aeb6c5611796f03b5cbd88ae92452a4727e13f4f4ac90130a58ac81821f89a959b0e3feb0768e7301b918a348227704a7685deb45c29196e4f4a1c2715327a127d08fb5d33a731240d35342e3138372e31342e3233321467e05b1b52c7c896adf20035036fe1d30dcefc9cfb4e1ffb05a3fb8f300030b3601dc016ef030a4707e2afd8669eaf547aed29a43a3c3f0a1f5da0f50d3ccf3717876623efaaf4fd01d56d4f19c4af200000007672f63d6d54737b0dc862fe00a4c146100e922c39e2b8349a48088d5200200000007672f63d6d54737b0dc862fe00a4c146100e922c39e2b8349a48088d5200fc00110898192012de3ea6678dadb1db529b7fa98762160625055de2aa34e757c93c136233f4a22012de3ea6678dadb1db529b7fa98762160625055de2aa34e757c93c136233f4a20130b868374061b0f68d2c262e87dc45c2bf048a9f3a9f6e91f51cb1b7fe623deb3709b439cdaec9a48519201cfaceaa3bf40e3231322e32342e3130332e31343914c1161c96de3dae28cd7f20ff8c2aa7b94b866d76fb4e1ffb05a3fb8f300020143dcd6a6b7684fde01e88a10e5d65de9a29244c5ecd586d14a342657025f11320143dcd6a6b7684fde01e88a10e5d65de9a29244c5ecd586d14a342657025f1130130b4915f6d8f4ddb2132ddeaa39ac3c7ee6a6e4e026d1a634c146c705a0a1e5303939da3957af20e322f32bdeeda3bf78c0d33352e3136342e32332e32343514b5f25f8f70cf8d05c2d2970bdf186c994431d84efb4e1ffb05a3fb8f30002020107ec50e81880dca18178bb7e53e2d0449c0734106a607253b9af2ffea006c2020107ec50e81880dca18178bb7e53e2d0449c0734106a607253b9af2ffea006c0130a962184d452a61d4adf3d719cda3a02eb6eaf1b7838144b2e0bd9fe8db237c14912369484d2eeed76159e9592604cf150c33352e38352e32312e3137391435d9eb76397d05b43b5cd8da7ccfa8408bc89ab3fb4e1ffb05a3fb8f3000202e48651a2e9c0cb4f2fb7ab874061aa4af0cd28b59695631e6a35af3950ef6fb202e48651a2e9c0cb4f2fb7ab874061aa4af0cd28b59695631e6a35af3950ef6fb0130ad0d7d5ef86215650c75e1b9b6773db96a06835508dd97590f56f8b678313f8fe082112bb8ced61e0ae797981ede6f7a0d35342e3134392e33332e313637141ffbf1d32541dcb8f5555305295704a9ff9adc24fb4e1ffb05a3fb8f30002039741ad83dd791e1e738f19edae82d6c0322972e6a455981424da3769b3dbd4a2039741ad83dd791e1e738f19edae82d6c0322972e6a455981424da3769b3dbd4a0130adcefadcab21ba07c09f07eaedaf087adf5b674028af47d1251bdc3cfcf032b79ea71e530caccb20361b9a5c25a440460e33352e3136332e3134342e32333014ec7bf3b9bc72eda38c80bb7cf16e294e763e56b4fb4e1ffb05a3fb8f30002040784f3f9a761c60156f9244a902c0626f8bc8fe003786c70f1fc6be41da467d2040784f3f9a761c60156f9244a902c0626f8bc8fe003786c70f1fc6be41da467d01308abf30d7c88c6104d05ca58f08fb61c70c3d655576b559a27c2b1baff75802b6bc99fb206db5473ebabda0bdf79bad400c35322e31302e3232392e3131143e8b10646ee9d6c28d75c280b357dd3a9ae9f962fb4e1ffb05a3fb8f3000205b246080ba64350685fe302d3d790f5bb238cb619920d46230c844f079944a23205b246080ba64350685fe302d3d790f5bb238cb619920d46230c844f079944a230130ae3b8d52b37ae8382811cf52d9b29fddd46fd66c098dc03df1857a50effa2c85674e195d4ae0ac22d25df111b9289cd50d33352e3136352e35302e31323614f460a07a2b0dc932e1d8ff2dee2b984ac415dcebfb4e1ffb05a3fb8f3000205c6542766615387183715d958a925552472f93335fa1612880423e4bbdaef436205c6542766615387183715d958a925552472f93335fa1612880423e4bbdaef4360130916c39a7d78a348ce8c99f798ed84d7368601612dce992277e945ee3d34308a70e92b08635258ca6cac8539355779f0c0d34342e3233392e33392e31353314972a33056d57359de8acfa4fb8b29dc1c14f76b8fb4e1ffb05a3fb8f30002061d33f478933797be4de88353c7c2d843c21310f6d00f6eff31424a756ee7dfb2061d33f478933797be4de88353c7c2d843c21310f6d00f6eff31424a756ee7dfb0130ac518d843f4893fb55f7db299c2fba948107223385f82981dd8aa4e073731029efbb116b85ebd2912f69e8a20b898ec30c35322e31322e3137362e3930147ada3e486409b39c94a0833c8d782f35bc24e96afb4e1ffb05a3fb8f3000206d1b185ba036efcd44a77e05a9aaf69a0c4e40976aec00b04773e52863320966206d1b185ba036efcd44a77e05a9aaf69a0c4e40976aec00b04773e52863320966013081730f2f8ca06b21e037e1413f4e07286daa61effdddffedb1e3d37be25be8f724a2c5cedd2267bc712e09ecc864b94f0e34342e3232382e3234322e31383114c374f016ea61e76aab79b8bb95a1ba0e6e3eee6ffb4e1ffb05a3fb8f3000207135069642e1a72807a383fb5a14b9af6758292fee53fe2a7f7ac6f528bf7019207135069642e1a72807a383fb5a14b9af6758292fee53fe2a7f7ac6f528bf70190130a666c20f678260e6cf732ca2d9c335aa7eee07e9a48f15fc52bc70a0e91bbbb601235905a7c2e94f7b73d4be85684fb50d35342e3138392e3136342e333914f9956e70daffa263e8cf29fa6557b7b630a595a8fb4e1ffb05a3fb8f3000207718edad371e46d20fad30086e4acf4a05c2b660df6ae5f2a684aebdf1be4290207718edad371e46d20fad30086e4acf4a05c2b660df6ae5f2a684aebdf1be4290013094813102a7c65673c8421b5098bdb3527a6374488c6e4005077589ea6d88cb978149246858b01f5c043b0db861bfd7710d34342e3232372e3133372e3737140498ade3c80045c2a7520e921180ae1c39da5c57fb4e1ffb05a3fb8f30002087075234ac47353b42bb97ce46330cb67cd4648c01f0b2393d7e729b0d6789182087075234ac47353b42bb97ce46330cb67cd4648c01f0b2393d7e729b0d6789180130a4e5e437e79ca948abb1c47d227e0cf431223858e232efc678f2f44c01b8f03fc8bfc783de1c9aa25fa33ff26e34683b0e33352e3136372e3134352e313439149b9cdbfe3568cc0b37f136b00a634c75653f05e3fb4e1ffb05a3fb8f30002088251bd4b124efeb87537deabeec54f6c8f575f4df81f10cf5e8eea073092b6f2088251bd4b124efeb87537deabeec54f6c8f575f4df81f10cf5e8eea073092b6f0130b96bbcd66fe7998497d85b794b7ac3db4f6aa623cda276bd5794ef34e187556fda94f0a79e9f821ef4c75c27366cd7480b35322e33332e32382e343714711fd9548ae19b2e91c7a9b4067000467ccdd2b5fb4e1ffb05a3fb8f3000208b8d1193afd22e538ce0c9fb50fee155d0f6176ca68e65da684c5dce2d1e0815208b8d1193afd22e538ce0c9fb50fee155d0f6176ca68e65da684c5dce2d1e081501308f492b943a251501373b176dfb18a0f7870823efe32b9cff53992283704048e8760a9000f26b94dd297621f8d8deba080c35322e33342e3134342e353014a0a0e17bfe82a484fefe348b7569a6d77d29d2c2fb4e1ffb05a3fb8f3000208de8b12952f7058d827bd04cdff1c2175d87bbf89f28b52452a637bc979addc4208de8b12952f7058d827bd04cdff1c2175d87bbf89f28b52452a637bc979addc40130b2079d4be290c58b34c9c14fbfd01bb9f1aaef01d002b319925a243335c52878ac883f9b7e0127271590188df43119f60c35322e34332e38362e32333114337b7fb5d2c531825c3e0123ac3354018085b302fb4e1ffb05a3fb8f3000208eca4bcbb3a124ab283afd42dad3bdb2077b3809659788a0f1daffce5b9f001f208eca4bcbb3a124ab283afd42dad3bdb2077b3809659788a0f1daffce5b9f001f0130a92f9d9f46f6c9553c28adbe4855f42298c48953fdceec62c7382ec7ded8e0bbff64efe7df4db32c7829f41719d340690d35342e36382e3233352e32303114c075993a8336f93a13bb7bbb7e0e89928be4aafbfb4e1ffb05a3fb8f30002091bbce94c34ebde0d099c0a2cb7635c0c31425ebabcec644f4f1a0854bfa605d2091bbce94c34ebde0d099c0a2cb7635c0c31425ebabcec644f4f1a0854bfa605d0130aef0a3f51cd505157dcdf018bf77412f70236117262a69892b426c48ccb906614b68adbb916310fbfe770b29c0e109ad0c35322e34302e3231392e34311402aa69f8ef6666e7cad6d9323755a0ef3c1b6bd9fb4e1ffb05a3fb8f3000209712e85d660fa2f761f980ef5812c225f33f336f285728803dcd421937d3df54209712e85d660fa2f761f980ef5812c225f33f336f285728803dcd421937d3df540130813f9716f1fefada2d1a750779935e9571bded5f0a2a0a08b19edbf4d821538999d4acdd537755599eff93717fa071430d33352e38322e3139372e31393714ed1131823bcea23ac78af8c01e4d24683d6ecf88fb4e1ffb05a3fb8f3000209cb04f271ba050132c00cc5838fb69e77bc55b5689f9d2d850dc528935f8145c209cb04f271ba050132c00cc5838fb69e77bc55b5689f9d2d850dc528935f8145c013095202e363e72de2c2f1824d118a6b19243808d4bf3090cd6ce1bcf0c92937f6b2665f05e497f0dd27586452f9e1507230c33342e3231342e34382e36381462e960a3f6b650feed98a266b3ccdf6e363562cffb4e1ffb05a3fb8f300020ba8ce1dc72857b4168e33272571df7fbaf84c316dfe48217addcf6595e25421620ba8ce1dc72857b4168e33272571df7fbaf84c316dfe48217addcf6595e2542160130b5ad25d83182aea77532834687bab1d6240b7b40a55ca27e60259c1e4f5077ffb26c3b1a0434d9eef529596d632c9b710d35322e34322e3230322e3132381462e0104ce0aafc1f06bde37c73702fe84b307f05fb4e1ffb05a3fb8f300020c11c1168dcf9479475cb1355855e30ea75c0cdda8a8f9ea80591568dd1c33ba820c11c1168dcf9479475cb1355855e30ea75c0cdda8a8f9ea80591568dd1c33ba80130b9a2cdce8e51b6a514e599ab5edda00e6d69fc0cc43c380915149abe7159f9c856e5ad391e7eb443ff8a5bfeed2659d10d35342e3231332e3230342e383514fdae7cdf38811659ce9481975b326a5d07236bc5fb4e1ffb05a3fb8f300020d9b090cfc19caf2e27d512e69c43812a274bdf29c081d0ade4fd272ad56a5f8920d9b090cfc19caf2e27d512e69c43812a274bdf29c081d0ade4fd272ad56a5f890130a5d068fa707cd7a1dae2b4e30f384a516e4b86bd69ea0ae40204f35235fe866a3f54e1f7460ed9744485b7744b58c4850d34342e3234302e39382e313032147034f0d3853c5351fb8e0ffd3c1daf12c51c2d89fb4e1ffb05a3fb8f300020f6496d3c0ac1ad94ff5e3aab2edcabc1c8ba3fbfea0ef3026e90ba786399038120f6496d3c0ac1ad94ff5e3aab2edcabc1c8ba3fbfea0ef3026e90ba78639903810130b11e5897513333cacd8b5761d884b08699da6d8dac9e965a366599813ab7599ea6ac86f064060761559940e2e1fad3ad0d35322e31332e3235302e31383214fe2d4798df3e9b41a6823bc0b3f020478e87925dfb4e1ffb05a3fb8f300020ff261d2c1c76907a2ad8aeb6c5611796f03b5cbd88ae92452a4727e13f4f4ac920ff261d2c1c76907a2ad8aeb6c5611796f03b5cbd88ae92452a4727e13f4f4ac90130b006eca834e243cfa364f0b6a127aa221306b1d3f51d29b99e673d69a2e6fe60e27dbe859bcd85ac786430a8cbd6775b0d35342e3138372e31342e3233321467e05b1b52c7c896adf20035036fe1d30dcefc9cfb4e1ffb05a3fb8f300030a8aa56233bd002f4e294ab97dd212cbca4f79aea9cf6e80ff7a568ed5668569cfb5dac816a3f8561ef04251a28fd530c20000000251c6293f36145e149a75179d723b88d675332f8efd1667cf871d246710020000000251c6293f36145e149a75179d723b88d675332f8efd1667cf871d2467100fc00110880192005b687978344fa2433b2aa99d41f643e2d8581a789cdc23084889ceca5244ea82005b687978344fa2433b2aa99d41f643e2d8581a789cdc23084889ceca5244ea80130990f9bdf2dc93b6566cc92ebeff39bdcc062a37575b737848ef93f040e09d8fc7104116a48c83376d050ef245e90fdf50d35322e32342e3132342e313632148feb00404d6f765856c95e587b2523a365bc7258fb4e1ffb05a3fb8f300020143dcd6a6b7684fde01e88a10e5d65de9a29244c5ecd586d14a342657025f11320143dcd6a6b7684fde01e88a10e5d65de9a29244c5ecd586d14a342657025f1130130a306779bbe3f86d7b731176aa1a86a6ee080adf527953a6844e02e668b67fab78e859690844d72aad89602d175150e3e0d33352e3136342e32332e32343514b5f25f8f70cf8d05c2d2970bdf186c994431d84efb4e1ffb05a3fb8f30002039741ad83dd791e1e738f19edae82d6c0322972e6a455981424da3769b3dbd4a2039741ad83dd791e1e738f19edae82d6c0322972e6a455981424da3769b3dbd4a01308db9d17923c5acb439a2ca05d6b8a9b8e4b68a0554b1a0325c926e92e13ea0a8c4c9a6f38bb16b9d7807532ef96064490e33352e3136332e3134342e32333014ec7bf3b9bc72eda38c80bb7cf16e294e763e56b4fb4e1ffb05a3fb8f30002040784f3f9a761c60156f9244a902c0626f8bc8fe003786c70f1fc6be41da467d2040784f3f9a761c60156f9244a902c0626f8bc8fe003786c70f1fc6be41da467d0130a660a964938e90ba91e8f1bcf46f5b61edf9e7bd1c974e7f58ece9f6806f9e6e6fa06301e75cdffd923089c78ecf5a610c35322e31302e3232392e3131143e8b10646ee9d6c28d75c280b357dd3a9ae9f962fb4e1ffb05a3fb8f3000205b246080ba64350685fe302d3d790f5bb238cb619920d46230c844f079944a23205b246080ba64350685fe302d3d790f5bb238cb619920d46230c844f079944a2301308e64b6456c41e771170854d8415bb95fd47c597373c00a55a4beeea43d6a22830e2e4c6dbe4dc03794e0c8786d9a040b0d33352e3136352e35302e31323614f460a07a2b0dc932e1d8ff2dee2b984ac415dcebfb4e1ffb05a3fb8f3000205c6542766615387183715d958a925552472f93335fa1612880423e4bbdaef436205c6542766615387183715d958a925552472f93335fa1612880423e4bbdaef43601308317d15d474b38602d5e3ec6d1c3da6284da53b47b5084534b65debf30c2018a048b3561c38429530a53f2ea5583de9a0d34342e3233392e33392e31353314972a33056d57359de8acfa4fb8b29dc1c14f76b8fb4e1ffb05a3fb8f30002061d33f478933797be4de88353c7c2d843c21310f6d00f6eff31424a756ee7dfb2061d33f478933797be4de88353c7c2d843c21310f6d00f6eff31424a756ee7dfb0130b09010ae7148d6459b2e3821ee2ea2e8c2077bd948a16ded93977f4865ba6d04a3e82ece2da5703d04e0d68fcec043610c35322e31322e3137362e3930147ada3e486409b39c94a0833c8d782f35bc24e96afb4e1ffb05a3fb8f3000206d1b185ba036efcd44a77e05a9aaf69a0c4e40976aec00b04773e52863320966206d1b185ba036efcd44a77e05a9aaf69a0c4e40976aec00b04773e52863320966013088412ab841f7b0951d6f0d035a9e91472983c1f66801e14ded8f71f7e6ffbf4d37ad1097cf4b2df332b4bf30ff5f45430e34342e3232382e3234322e31383114c374f016ea61e76aab79b8bb95a1ba0e6e3eee6ffb4e1ffb05a3fb8f3000207135069642e1a72807a383fb5a14b9af6758292fee53fe2a7f7ac6f528bf7019207135069642e1a72807a383fb5a14b9af6758292fee53fe2a7f7ac6f528bf70190130aec0362b40aff3bd20153844977a6b5178c8f4a0b59d13c3331c1713a984d9d0fe4e33bd73892fc7b9db0276f04822dc0d35342e3138392e3136342e333914f9956e70daffa263e8cf29fa6557b7b630a595a8fb4e1ffb05a3fb8f300020754b89dae8db20fc4cee5e3adb07b146d7efe508a66fa0a8e1094675b9daa35e20754b89dae8db20fc4cee5e3adb07b146d7efe508a66fa0a8e1094675b9daa35e01309757740efe454850a7e553e29ec92082f41c8559c209738e4bf2622856ce8a25c982715ab6b6b51224ae7b98f822e4b80c34342e3233332e34342e39351446d938862af6d9a291e26c0048177db2892a710bfb4e1ffb05a3fb8f3000207718edad371e46d20fad30086e4acf4a05c2b660df6ae5f2a684aebdf1be4290207718edad371e46d20fad30086e4acf4a05c2b660df6ae5f2a684aebdf1be429001308c41f9e11ecb851812be5235cd0cee625e9bebb624583096ff39a673d20f589021c6f3870191bbdafc32ed5245738b520d34342e3232372e3133372e3737140498ade3c80045c2a7520e921180ae1c39da5c57fb4e1ffb05a3fb8f30002085f15a31d3838293a9c1d72a1a0fa21e66110ce20878bd4c1024c4ae1d5be8242085f15a31d3838293a9c1d72a1a0fa21e66110ce20878bd4c1024c4ae1d5be8240130af5da56ee0a828c4ba881d28c2adc2ae288690fe37535a075ba54b72c6532c26095cc71d80f681d725e063d1f500e06d0d35342e3230312e33322e3133311468c506d43816d1a8389c860c1d162be44d1e777cfb4e1ffb05a3fb8f30002088251bd4b124efeb87537deabeec54f6c8f575f4df81f10cf5e8eea073092b6f2088251bd4b124efeb87537deabeec54f6c8f575f4df81f10cf5e8eea073092b6f0130a51dbf35096235fe2018a7f1ff00c3c18e541e6e5ae2a81c0952ed5a3c8800e1e6b5632ec1dad41af24c0d9bd8cdd2b00b35322e33332e32382e343714711fd9548ae19b2e91c7a9b4067000467ccdd2b5fb4e1ffb05a3fb8f3000208917bb546318f3410d1a7901c7b846a73446311b5164b45a03f0e613f208f234208917bb546318f3410d1a7901c7b846a73446311b5164b45a03f0e613f208f2340130b8f10efb4b60b6a2cc781c0f894151e0053e764175e261c75af516ec1cdab766de87b69453a73be3c234e6f4aefee6fe0d35322e31332e3133322e313436145bdbf34a0dad860c6ec71523ae39373325225cc1fb4e1ffb05a3fb8f3000208b8d1193afd22e538ce0c9fb50fee155d0f6176ca68e65da684c5dce2d1e0815208b8d1193afd22e538ce0c9fb50fee155d0f6176ca68e65da684c5dce2d1e08150130afa10520f621ca2cf4ee8ac229f9ffafdf0837f802eada2a823255235841f08544fcdb989fb4bff6348de6bb6cce8a0d0c35322e33342e3134342e353014a0a0e17bfe82a484fefe348b7569a6d77d29d2c2fb4e1ffb05a3fb8f3000208e11eb784883d3dc9d0d74a74633f067dc61c408dfdee49b8f93bb161f2916c0208e11eb784883d3dc9d0d74a74633f067dc61c408dfdee49b8f93bb161f2916c00130b1bf5c07ab8dbc65148edb38632459cc79b85290185b7bd6870f9352bde07980986a5427f783cbe3ec3946a5eeddc3300c35322e38392e3135342e3438146d57707c196e06487d326094c964f258f5b77c35fb4e1ffb05a3fb8f3000208eca4bcbb3a124ab283afd42dad3bdb2077b3809659788a0f1daffce5b9f001f208eca4bcbb3a124ab283afd42dad3bdb2077b3809659788a0f1daffce5b9f001f0130a56d524c550f683ffa4aa0be33fdd59b3b02b6c46bcf4696283da657d2d7581cc4ee52a38671b310d7d7e526f7f4557c0d35342e36382e3233352e32303114c075993a8336f93a13bb7bbb7e0e89928be4aafbfb4e1ffb05a3fb8f30002091bbce94c34ebde0d099c0a2cb7635c0c31425ebabcec644f4f1a0854bfa605d2091bbce94c34ebde0d099c0a2cb7635c0c31425ebabcec644f4f1a0854bfa605d0130a818137a518d06c03a98e2bdf2fe4fbef96ebcda3042504d109feab8c28692fc8d521de2f3cf75e3a412e09f9dbf17a30c35322e34302e3231392e34311402aa69f8ef6666e7cad6d9323755a0ef3c1b6bd9fb4e1ffb05a3fb8f3000209712e85d660fa2f761f980ef5812c225f33f336f285728803dcd421937d3df54209712e85d660fa2f761f980ef5812c225f33f336f285728803dcd421937d3df540130a94edfaa78eadaa7cad31be5997fba9465def62ae4e6abd5b94483b67836e61b418ec9288e3e5d928cfbd70a739928530d33352e38322e3139372e31393714ed1131823bcea23ac78af8c01e4d24683d6ecf88fb4e1ffb05a3fb8f30002098ef58c338a0a68e4f2f1d1ee9eb05fcafbb9177d192dac0f698d3d9ba0920962098ef58c338a0a68e4f2f1d1ee9eb05fcafbb9177d192dac0f698d3d9ba0920960130b59b4cef03be4158392249c56d61e50a21785005ba8982c4afa93d271bc4d0b7c19415013cdea9403c23c4a814aa1b920c34342e3233322e3139362e3614d6ece912cbf02627a4efc3dd37e6833cf3671551fb4e1ffb05a3fb8f3000209cb04f271ba050132c00cc5838fb69e77bc55b5689f9d2d850dc528935f8145c209cb04f271ba050132c00cc5838fb69e77bc55b5689f9d2d850dc528935f8145c0130885910160755543c1bbe191ccc79fc8eea5d6683a2186fa7666ad88caf4fb08c6c92b7baf1db457cdc11956e35b8a2050c33342e3231342e34382e36381462e960a3f6b650feed98a266b3ccdf6e363562cffb4e1ffb05a3fb8f300020ba8ce1dc72857b4168e33272571df7fbaf84c316dfe48217addcf6595e25421620ba8ce1dc72857b4168e33272571df7fbaf84c316dfe48217addcf6595e2542160130ae0682a10deb1a2c80076b617e220491c372ec9b62870789b419914c56f998ff30fc260ed11569e6ed864ef5774d95ee0d35322e34322e3230322e3132381462e0104ce0aafc1f06bde37c73702fe84b307f05fb4e1ffb05a3fb8f300020bbfd0ac1977011267a7032641ef5487fe15a4de798faa485b156fb3b7eb0acb820bbfd0ac1977011267a7032641ef5487fe15a4de798faa485b156fb3b7eb0acb80130a9eb13ce08f590b3346f9f6f36ec10a7860e3c1eae70c9df7663772224a60c7773f83ea2f080d0f74ae67ba223a9dec90c33352e38322e34392e31393614dbbebbc52a5bae21b818e0487311041c91b2683bfb4e1ffb05a3fb8f300020c11c1168dcf9479475cb1355855e30ea75c0cdda8a8f9ea80591568dd1c33ba820c11c1168dcf9479475cb1355855e30ea75c0cdda8a8f9ea80591568dd1c33ba8013095e62cf6ff14e6d8ef16761cde3384fc19533ea21e46001b57181b7af678eecaed015cdc58d10c4de4acfc937b5f18ac0d35342e3231332e3230342e383514fdae7cdf38811659ce9481975b326a5d07236bc5fb4e1ffb05a3fb8f300020ff261d2c1c76907a2ad8aeb6c5611796f03b5cbd88ae92452a4727e13f4f4ac920ff261d2c1c76907a2ad8aeb6c5611796f03b5cbd88ae92452a4727e13f4f4ac901309338650338a17c01b5b225d5618187861fdfb4ecee36d56c141ffc55a5b1f31120fd0148f8f50bb071734375ac888afb0d35342e3138372e31342e3233321467e05b1b52c7c896adf20035036fe1d30dcefc9cfb4e1ffb05a3fb8f3000308bbe3bb70f3f0e4204b96c4ab65ee2574d35ced1d63e67379d9dda4017504767ac94148797747faf41a1532578e2ad400000180018180000000b8cd4ead1ee12d25126921d918020cd77745d9cce5b59f7287a2a296e309860460119622e94b562c3dcec8445e63d04f8f88d4d0835358f79ced0342b43822e32a35c32ebdf76eca5d940a999480000000021160aae5b92562c94a5d6735c5dff3a92aa0a8d9b02aa0c614ca7154a30b450abf6838c0026c4a8526d7dcb44426b02f225d98ec9d43bbbf91a204b9c50252b2e3c9af4c237dc117d73fd60345100000000251c6293f36145e149a75179d723b88d675332f8efd1667cf871d246713086fb47b84caacf7734799c2106fa87d8dac68bcceefa3fd33dd568ecbd7bae3fe312835eff8d68b9bfefa852d12589cc0000000029787a10cbbd05260d3c7a8114746b568d0a5fbd2fdb9f080ac12c5acd30a53f79f722b98c47ce515144b41daa3a97cc7176c456b05fee6d5fd0216e123c07b1c0ae5eccb6d637d88e9d45bd544c000000004689a842c049d460ee314df1bbfa36530ff86632142fe3b6eee824003430a0fc274fc7b00cebe08b5a91f39ff7435b0d944ba82abb5a3df6a768051b674fcda0c9ed7478801f58abb1d081319e3c000000004d43bd84ac6be16b9b7e352b3e9905e1337d7d4d6dd0b8a0ff92a89f1c30844a36bc9a23cadfc278a9cd6df42b375ce2080c106c8ce01b3aefcac3f81ac3ba2abd5208165ff95039bed9d8ff94ab00000000503099f9f7fc49ca9350ce1951c09325670b8b459f3a55ebe6811f13e1308c43a90fc0e9a3b85297dfc221a1edd2b791c03bb2f5cda875a8844edfb73d8548bcc3be5ac5cf6548b9023fc551dffa0000000050b5530a426cc3a37ae64b7e37879c0905cd90391226fd7395a19cad2b30a99406603295d31f2f2bac6c2cf95a3b950b7abbdf74928010514d2ec53a5c4d3111fde6eb703f6e5599bddfb6ef2de30000000072da33f586cdd86a566cb30268f411dad855dc3fd18c5669410c7cdaea30935e67335f895fc17481cb14a4cf7976d449446bc45714c8c33888228d1a8833b372f0bf5e57d3da8d8b46a3df24ba18000000007672f63d6d54737b0dc862fe00a4c146100e922c39e2b8349a48088d523084fd520baf70c5d1f099f89c30e4824cf9307db2d50d04ad055a3cd4b1ca382e097615cb41a814d6c8af1df3f41ea40e00000000b6ebee5a8f801f7b66c32a3454b12513c76ab58b121a4e9c579bcd4e8c30a073fdd826b6f0528d57640ed2c442f427ae50365c8ee533aea561a43f0a847535d1de724b4cb33d8f1ebb1b7ec1fee800000000b91e2a2fe9ab4c3899dc7d2d85c9e00e068603afe59058d5415a84773d30acdda79998aa4a7c8db61e4de0c0033a6ad68b8e898017a0a1e478204a9fff434dc7d874a4346ff3f0cad0e6d6a7f0cc00000000c9c3825db4b9a1751e94ef41634a33e2df66e8f9ddcd56dd435232f48f3097fbe82232f01d505db016f9acedd89b3b64aeebe3ee42c618a70940c223b44702d47289706c066001f399911b13e5d900000000ca47540e3e2bbbfc91ad3581df6b5f730ea457841a3544e2ab3c54c24530b81e791bfd854cadc0ade4456d2eb225c921545d3c6511771be3e41f96b828e14fb560a4c8d86eab9935b6b3f7dfa0e000000000ceb90097be7a897c47be4752340dab3c394e860cac4f03f7bce60caa8630b594ee3dce15b395606f54f5269d69688c38b90958253f6f75897a312849d64f5f991600032a11b4f44162d429a08b9b00000000d4b6e3c3b706bd8941885c8fb46dee63ffbe116888d8892b7f53a0a0da3085a9c445b48a8fd3703c240ac3c838f65f78f6208698dc651d1a24ea3f09a72dc43389bea4e65f4576708b39f139b9f100000000e5d8948d2c695de557f1327a8f323fe00ea463ab53d415589456cae543309428bbc401fabb4f3e7c3a6a5bcc139a4ae581645729bd4dee7f272446357cb0c4064ffde38e5eed63720df03259ca7e00000000e7654d577ec30cf6779bb7f025807118c9ee33113ea249fa1ce949064630aee6aa85f79fefcde7fb71a8c880f6474fde2cbfd5cb6d1afe1cec9506fb25b1f8908e1934648898c79dc403f2094d6300000000e78672b7a792c03ffc5e06c6512e0ae64c4b5410a2e41b6b871036e5d330a89228f3c8f7b8cc5080b6721668c5f6ffa0c6b7c7fbd6182e968882e6676a436d47ea673c2ddc83aa6692c44972a6fa00000000f1187cb12e35cb2a20fa7ebaad86a10a07f37a26d91068fcbde0ee462d30a7bbbc25d144e31734003aa26cbb696ff91d5895c67110369dd24998e7da857bbe7a40a9086b96752c1e35e19a485594000000010832789d4cdff3cc8a63fad668ccac708af7433c42e189ada6c6e5e66e3083e592e3320143c10ef29d05f6094f428fbeec17671057917f2bc2f6d71f8151e3c22379c9414e41f568a0dad43a49a2000000013b5860da205d4132c60deedcd2f06f18c77718fc9f96a5473d05e596fa30b64e26f35b32ed7fcdbf760a3806137ee21208642ee072e3284df4a1f9197b2b2c1036a355d2fc670b37f6d06631195600000001561ac909f7762f03b801661c0ab46943d603d2883b36535ad5f6344cb830a9c57b1671efe72ccf52577b20fdee42c4f93c2098dcce5e0589b4eced2a1403c4834084b950f775a23745c73f85edfe00000001d6bd1fcac1f64325a6a26b0a3a02d1e3b61267d50f855984a873c3d689308c3f90fa3b27af67e8f0b3078169ea2cc61ef13b075fd8e0d2d6a7e83ccf0c59370020e5c753a0ad1a684efcfd68499a0001180000000b8cd4ead1ee12d25126921d918020cd77745d9cce5b59f7287a2a296e309860460119622e94b562c3dcec8445e63d04f8f88d4d0835358f79ced0342b43822e32a35c32ebdf76eca5d940a999480000000021160aae5b92562c94a5d6735c5dff3a92aa0a8d9b02aa0c614ca7154a30b450abf6838c0026c4a8526d7dcb44426b02f225d98ec9d43bbbf91a204b9c50252b2e3c9af4c237dc117d73fd60345100000000251c6293f36145e149a75179d723b88d675332f8efd1667cf871d246713086fb47b84caacf7734799c2106fa87d8dac68bcceefa3fd33dd568ecbd7bae3fe312835eff8d68b9bfefa852d12589cc0000000029787a10cbbd05260d3c7a8114746b568d0a5fbd2fdb9f080ac12c5acd30a53f79f722b98c47ce515144b41daa3a97cc7176c456b05fee6d5fd0216e123c07b1c0ae5eccb6d637d88e9d45bd544c000000004689a842c049d460ee314df1bbfa36530ff86632142fe3b6eee824003430a0fc274fc7b00cebe08b5a91f39ff7435b0d944ba82abb5a3df6a768051b674fcda0c9ed7478801f58abb1d081319e3c000000004d43bd84ac6be16b9b7e352b3e9905e1337d7d4d6dd0b8a0ff92a89f1c30844a36bc9a23cadfc278a9cd6df42b375ce2080c106c8ce01b3aefcac3f81ac3ba2abd5208165ff95039bed9d8ff94ab00000000503099f9f7fc49ca9350ce1951c09325670b8b459f3a55ebe6811f13e1308c43a90fc0e9a3b85297dfc221a1edd2b791c03bb2f5cda875a8844edfb73d8548bcc3be5ac5cf6548b9023fc551dffa0000000050b5530a426cc3a37ae64b7e37879c0905cd90391226fd7395a19cad2b30a99406603295d31f2f2bac6c2cf95a3b950b7abbdf74928010514d2ec53a5c4d3111fde6eb703f6e5599bddfb6ef2de30000000072da33f586cdd86a566cb30268f411dad855dc3fd18c5669410c7cdaea30935e67335f895fc17481cb14a4cf7976d449446bc45714c8c33888228d1a8833b372f0bf5e57d3da8d8b46a3df24ba18000000007672f63d6d54737b0dc862fe00a4c146100e922c39e2b8349a48088d523084fd520baf70c5d1f099f89c30e4824cf9307db2d50d04ad055a3cd4b1ca382e097615cb41a814d6c8af1df3f41ea40e00000000a9510131c07fb58ce1f572165af5af245f7be594245cdc40b7b4b95cc7308ab76c9e9a341d200635323b462be31199e93cd43bfeecdc1243d7c8d1ba41910edc07cf6f197d55da1f5c760dd661fc00000000b6ebee5a8f801f7b66c32a3454b12513c76ab58b121a4e9c579bcd4e8c30a073fdd826b6f0528d57640ed2c442f427ae50365c8ee533aea561a43f0a847535d1de724b4cb33d8f1ebb1b7ec1fee800000000b91e2a2fe9ab4c3899dc7d2d85c9e00e068603afe59058d5415a84773d30acdda79998aa4a7c8db61e4de0c0033a6ad68b8e898017a0a1e478204a9fff434dc7d874a4346ff3f0cad0e6d6a7f0cc00000000c9c3825db4b9a1751e94ef41634a33e2df66e8f9ddcd56dd435232f48f3097fbe82232f01d505db016f9acedd89b3b64aeebe3ee42c618a70940c223b44702d47289706c066001f399911b13e5d900000000ca47540e3e2bbbfc91ad3581df6b5f730ea457841a3544e2ab3c54c24530b81e791bfd854cadc0ade4456d2eb225c921545d3c6511771be3e41f96b828e14fb560a4c8d86eab9935b6b3f7dfa0e000000000ceb90097be7a897c47be4752340dab3c394e860cac4f03f7bce60caa8630b594ee3dce15b395606f54f5269d69688c38b90958253f6f75897a312849d64f5f991600032a11b4f44162d429a08b9b00000000d4b6e3c3b706bd8941885c8fb46dee63ffbe116888d8892b7f53a0a0da3085a9c445b48a8fd3703c240ac3c838f65f78f6208698dc651d1a24ea3f09a72dc43389bea4e65f4576708b39f139b9f100000000e5d8948d2c695de557f1327a8f323fe00ea463ab53d415589456cae543309428bbc401fabb4f3e7c3a6a5bcc139a4ae581645729bd4dee7f272446357cb0c4064ffde38e5eed63720df03259ca7e00000000e7654d577ec30cf6779bb7f025807118c9ee33113ea249fa1ce949064630aee6aa85f79fefcde7fb71a8c880f6474fde2cbfd5cb6d1afe1cec9506fb25b1f8908e1934648898c79dc403f2094d6300000000e78672b7a792c03ffc5e06c6512e0ae64c4b5410a2e41b6b871036e5d330a89228f3c8f7b8cc5080b6721668c5f6ffa0c6b7c7fbd6182e968882e6676a436d47ea673c2ddc83aa6692c44972a6fa000000010832789d4cdff3cc8a63fad668ccac708af7433c42e189ada6c6e5e66e3083e592e3320143c10ef29d05f6094f428fbeec17671057917f2bc2f6d71f8151e3c22379c9414e41f568a0dad43a49a2000000013b5860da205d4132c60deedcd2f06f18c77718fc9f96a5473d05e596fa30b64e26f35b32ed7fcdbf760a3806137ee21208642ee072e3284df4a1f9197b2b2c1036a355d2fc670b37f6d06631195600000001561ac909f7762f03b801661c0ab46943d603d2883b36535ad5f6344cb830a9c57b1671efe72ccf52577b20fdee42c4f93c2098dcce5e0589b4eced2a1403c4834084b950f775a23745c73f85edfe00000001d6bd1fcac1f64325a6a26b0a3a02d1e3b61267d50f855984a873c3d689308c3f90fa3b27af67e8f0b3078169ea2cc61ef13b075fd8e0d2d6a7e83ccf0c59370020e5c753a0ad1a684efcfd68499a00fc00110ab1fc00110ab301fc00110a9c00042001fb0120200000001c17557b0aa6d56b745b60fd4c3c53f2beba8fce58a6a01fc50fce1cd630919fdb493c7492c92651b5b48643001974e9c6c08dc38d201e914672732b7e237f81a9a883cdc12b446548823fc52769011600000024dd142c3b883d9653935780d82dfa760af504be48745a9ccfeb87f95e3080fb2822996190c9ebe6ef941f7b9c2cf140117614926c516865791a2713ea6a773751e9753b0ed63849763e435d027d0102000000372aeb94a3ad89154fc41c296b1bfbd2f744934dec354ac9f121a3c2f730ab6d16078b0190e779e516e9119abcc0623d14034dd8cac836d9114239251a0d10a77e498c92db7894d8359ebb8fc628011d00000037608455165b3d7f752e5576bb9e3fdb54af8c9f6aea8c5c39f607ebeb3091199e5de7deeb39bf99ff557a5267ee0fc5e4297089e1ce03afbe27d7a4ef75196c6e599e4b15314213368b00c3cee4010b00000037e2a2a37e026777d2ba67371b1dd0c7d49044c5a566f0469be085c16f30a184eebcce47f63dae0e2a55a74afbe53b671b6fb9954936fbd17bc890ca3f0e769983b188a22469c394c9bc1dba8a6b011f000000411dd2ec65ed0f979acff00da0df586357e715de8ca3b2d42cd39614573095598b486466ed807f4306968b15410d4a55cd1e38f7bc3a489b1056ba8eae9a6dd5e1ed9e59c772cbf5da7e8b8c293e01090000004be4965bcf4d4e63c8250f81c617a58a5a268dc8ea3c3f86de0b3a806d308734df8c4bb9757e5157ef809535296800a14c76a4c925dcc26f74efd78bb45974590efe53d6d12eea41c1cfaaf5dd90011e0000004c4be4ac378bff06fc33e9677589e9cd45fe403dfc27c7874f95d42a6b30ade14cd45e426734de61d95bb6ffbb1e64e7c3dd3e046d3fc0d39edc28e1f047c07e44ca7fda141356d35119dcea53210119000000504bcfbaaf0684b5f9e5b43925497de07e93444da15568fd67daa3e3ca30b885843723894347bc0bb59761178e34b5ed29b879e23ce3bf84d60de0fab9e4d2272106f7c83799a1350ed11859df1c01030000005634442336d250bc6f41a1beb3150bf00c4386e29c782c86f64e524af7308422c8690ea530d4c1c13d841bbe24ec66d82f1b962ce39241ad45c13a62ba4aec66bc80b9d3ba52642b9ec7d471fe06010f0000005a8b5ca058cba2953dc80aa4485f2acced3922c29d3388b167cf78b35730965fd8b4db515a89e27c43dc591d47e343edb967d52fb8f1423fbefaa91b97fadb131b99dbcc28235ff0879dbb6a42df010c00000066677ad0a47afd2836cfd9b29a60f2a5f5b76e27cfc5fadfbd9a56a0d33092517556cba9e44f944d656e0bd15062b41d172f9a3ecc7fee1d79909e3dd9929f5120dadb0d6650a92b0ddc4e4d1fd6010a00000097e09e2749e43066a7ec3e08da9786b4597ec68aa764a5b12fa994209430a03cc310e3d46343430851204829272c534ceb7b9bf0b774f8e00148932d1c6d7e9bf4e1616cb943aa44fd6010b147e1011300000099f4ba9b8f567066725e949ae6d15af33124f288930c05f29e5b9c63ed30a473df3015852e967e3365b140353ce5800e15abdf8c7736e2df5304a779b7e588b7d72423c9901004182809f64008990107000000a8d450eefbf6324878ad6e6203ca409d206772a0e83910352e76e5478e30b72a08760cb1af67a0881b13d87f4f746b7e782f9c4dd8f61f7e25ab359fae768a25cbab2004fe9a095e9e97d8fc6f3b0114000000a946faee14ef3fe5b06dde3132766c3edafcae89fdb534c2c2d0be155c30822fc04e42baae578281253c438dd9d8611f0bc325b9a9e39a2ec8b952c963401dedf25fa2cbc8ef26c7a5783c2372f80106000000bce166b1ab589a089dcf9ea84bbf00c42f3b2699aa067c53ac6a942ae63093025ddc9b3f01449f67864c0b9cc26db0e8526d0c08035ce8151aacdb204b0d0c33aa7b6462a5d09b3b00f1783183b5011c000000cac98a5ab2a2156e2648bc99a6eb514aba8d1a46167cdd21baa11488033090c1cbb77a5995d55907bab10d33eaa999219dd3751385d9259dec972208a6789b2ba31e2c254889895508fc077212bd0104000000e2113e90d0ec07975c2aec2c8afe986477d1eba19a7811d5d33b1d448630b9cc6d95122f1c1ccdc7b5d3171427fd2b3de05835649902ace1f73788e4939aee450e72209b9c6d28910eefecb7335e011b000000e3b9c3ac893562d87389c0255c7f95a51db2960302fb8d6c9d82972567308b82f0157d4eecdca9a865abccf6ead67a65478b29c4021e15b26210880552bc61cd7762c8203d6b7cac79f6ec11db930112000000e42610cff0fc6648d1cd6d4d54dc3ffcecb374e945db637b7fc7e1094f30acb1a3b40966809d190d78514794ec2062ac3a567cf878513f8c2793bd555ae2107a1be0e09e4c35029aeb5104d8e5be0117000000e7654d577ec30cf6779bb7f025807118c9ee33113ea249fa1ce949064630b51b3d77bad620570ddfc765e459c508e780168c1e76c2ba6b3312a21a0e9da0b54c7f26331d962c30097ac89f4590dc0118000000e8528886d471e749c483155d887f9c8a50625b0263103e18dd0771d8aa3086ece6336903315a8e34688eff6f5534bacd3ab8f6b3364738467a7b26079acca871dded3d3b402cf90f2f9f71375fa70115000000e90fdf133f8cc78262509b2dd44809d0cfce8c8d895145fb76aa72994730b20fdbe02732421192ed34d58bbcc7252869c16480638a4d4f95fa35b39ecfc914960b1f883a3503e43ae29913ba8a33011a000000f4fee40e6c8b309743319b89d273476ce3f480adf035ffe6d35680c03530a51f0d204efa8aac21d376a7fe892d270ac5ac1d8b6bb2f2633c358937ebc950a120acfa13d51358e2edf9d31099b5090108000001027d7fd3b22fb92e73d2148ce965d2e3684a7dd241215bd01be45764943091c2b79dcb3d7493c35b41838867fc468d5c691c8835f643acb2a75eb438d8fe64d44ecafe51373514f2b2bdb8c1e55e010e000001082689584968c870268b47d0d3d3c7ae0655fd1ab678ed72d359cf1a67308b44174aada80c6112c7d703a4e60a76a837432a45142f02eaab5f5b7ca558e5bef1c82f7554af04394201960fa7ec0c010100000133375fb619887caee8dfe8c764a3ccfb10a2896075d79b55e00833182f308f11d173cd8faa2a60f2160205ac5a327c62b5b0796eb5f479eeb08873039c52c619d5066f30625bf757f01ec4885b4c01110000013337cca3c54b9ee0d086cf98c4ad8fbf2912a8281d31b5bb675b9ce1e73089a581df737b98b4ee8329a7ca0c38684dd6c6bbdfdeaa415dd7f26251b0571f9a33f25d9e83e55661918ec38fc752ad010d00000135fec3b0a50d647054092ac6dbdf51f4b86bcfb108cbba6d6f3deec30030ae5fa9750ead0aecee2ed5ab68056870a6cc8ba46e9580080325a8c418eb1e747bc165e504beb9ddc5ed4ec168516ad30110000001d60371889ab189c71d65fab144450f460ca502c1fc0236947a11e69715308f00f47f5a43d0c0f1f3c34ed98e9570b2db010ea6586e49b72bf68060b926ffdbef76c2bc4fcd53116a26c02bbc3ed00105000001d6bd1fcac1f64325a6a26b0a3a02d1e3b61267d50f855984a873c3d68930a51f3fcd0dbcfb1a8283e2e476a24dd722da031ad8c800ae359757c57ec4f939cf1562f5337c6863140b862d7aed3eb80100012000000003b8ac2b8c34bb5c5e581b140305c9213f8e269d075f7c3ce35058657730938107a9ea8b35489dde14f2d2107fe95a9c6a6aebf73f4133a5e8a7896434fd44f8770d6ca3901938ba36bc244079d801100000000ebfb3fd8682d13b42d76227518da219365299bf25f60e060228c3c4f03088234afd114926aa4b1e7c279f29bd6b929b332025998236811a4afc1a64a8bf319580bcab4d21f0281c090583122352010b0000000efb7bdfeab3aa6b9a7aade1624bfe5139dc053648fde77414e5d0d26a3082a519cc0363d0b7525fc99c81ab531a06d4008d1371e9b9bfb0326a39a35250e71c6f546d48502e529a9904afe1f8de010900000015c1b422d89b76d662e8878f1e898e0e52bf1c7e4c8b5a5d84819e58bd309585750dd1e0e508b8cb449030845947a2cc2ba0fe61ab0d0d42cd4d3369789d9baa599618886ccf46d672ca96fa0177010a000000239040f5760172bf089991bdd423d77fe12ed94c6d6cce4e4ebaeea24030b1804746481f8b92b0f9031caabccc24ac90f83d050208a6d634a6e91612627c7ebd6862ee169b010e66c139c92192190116000000251c6293f36145e149a75179d723b88d675332f8efd1667cf871d24671309452257af9160aae311e167e55120f056c1ecaab2d83c920e5ad61904c7d308eb7309b207e91ab891a211ee4170b7d77010000000027d6c573e287f6815e8d549b7533b43d565f194fa4707c2c452c5efd71309992d9ae0daec52bd07358f00829c9e3146e1e43aa093670a89793feefee6668526097480e2840781f18e35565a106a601010000002864d8f7a309572aa28f644fe14b35996a6e4a277b7e2d4a61c869df6e308a37b3962e6a9bceb12c0456e65fbcdc8bbc1ce74a93f3be699c0608253a3674a8a4b6581576b57e288082732ceeba1501110000002f841c6f9980ac707036873109f38a5dea30d9b7b4440b5f39da05a69930a13ced5397b305ffb410d814d7a13d1f2d9e4cb246d2a9c1b67c6d00abd8fbd8ebc3a95255b3878366fce78f8446bf62011900000038975f7c98f3b1d4520cff75e2cd2fa8cdc1b2ae5ec173e8e3526fbf3e30a2f847e67c532dd711760aacb2ab1014655c197abb1969d2a35906fbcdc1df36f4653d0867a8ba0245f377a30d49c30f01120000003fc35bec19e30621f4df1807cdbdd46e7c2ee5fa7e3d16373604222b693099ef5fee5370fa30abb6aebddf9d70fcaccb586405ec9b0db02d068bdba05aff6d31a00cb7327a98df9b43543fb7b4990105000000568e1d35844bf5d087f1e09cfba371602447652743af5405fbd011418c30892f812b0354223bfd407a021e7ddada119fad9a78577ab35f7470b296b1447f813782c20cba5f7704f25c860601cd8d010300000058d4f48f9b03d5f56a1bfeac784020bec3fb8a158d5db64edbe3ec1d2330b261c3f2146141eb69446088de98875b7de7fd24b33bd411ea0bc2b1ae81057503afc3680af273dda36bc16e0c009cfa01130000005daaf8a7fdd8cf47fe818294ee93ffc2f3152bdb8d3cbf6defdbdc42ee30b9428acd63393effd14cafebe45395dd1fd1fa629760b9865dcb2e439d18c1624a3b0e4275ea86ef397078442866f9a501020000005f1c7c759087736e3790693baeed92291652f555159fca5df6ead3e3e430b66abbb198f79e638f60a65b2e8fa5d16b69fd86745aade4f1646d3ef6b9310a143cfc9f2d34f74185e01ad49b859a3101060000006c001fa7195e51d929c1007cb5529543fc5bd3e5e5f3d04fa580a118cb308c7271e6b940b60ee8779d1e17f9e4af1cbfe4002ec3f56485d1e126862d0bd67a30fedf00b79d1f7c33b2b9c6928f31011c0000007672f63d6d54737b0dc862fe00a4c146100e922c39e2b8349a48088d5230a14bcb0c1c0ba486a22e7f949c5d2001bb19574d61c7978e7652ee0b87579836cea127d01f2b30cf13a468cdcc9e56a30118000000923d006513e9f6f37a420a38601150bc26d58e5fc2fa90ef3de096ad6f30aabfe8dfc0aaf0f181eb03d5e6a8f3582fe0e87bcd0a6058c60ea4087a3f30bb71254212b5bce14217812204b58dc2500115000000a61f54580c3b3aedfadbdb39930754eb59740e06878c4b21e077b1779430a3133fb93de26128c7bc8558c07a701dfd34a8e7fd27c314e8200b84b90a3b8a51b90f028fa19c9b968494f1dc2a7897010d000000a7e630c41fc945da3e67a106656547bd01bb26a94664cfd9fa939f5b213089c5b215e5fec1fe83d2981940189f99f0bc5b4ba486061b76ac78d3eadd91fd75b4fff44af75302c889c6f05d3ecb080114000000a8995453aa34952a7b6a36d6668b30a5a60c552463546daf9fbac737b330afa30a9e33607a758b18ea83bf64da1564f374e6c92860bfaaaf9951489bacd7dc1e939cf8ec833a58b5f5d9e606c98a011a000000a900df280c8aae91f937784f000311185df27d367735d38819e417f27230848e2ce2f08bd3b353728ccad3b745f1ce0ad43a9bf09fa84197777b874d8cbfdb6d5281e478835e656b1c25aa294306011f000000a98c40586e7e085eb8d9c5cff72b242266ed2c422950e03b3b6324c15f3095a2759d436fbd36219acc6ad722cb88cda15acb23452bfc80adff6d81501ac7c2d6699fd7f19c60baf141a545fdf65e010f000000ab19860011844cbc2b934da040a0905e91cd35c37704ff8ceee8d0823530a87362c64e1d3e7a56a82005512bfa53ead93ec50cbd20b316708a2e826524138a4d31cc3c156027608079226de7246a010e000000b88bba6c313f883b01ce114e6ec70d6c4e41846d16eb44e06e49d543a23094b6e8291c5a475ed15351e29b983b396ed28e67e6c6e3d9bbd0c82b99aabd1bbd4522d664ab75172bf1b1dfe2d784bd0108000000e8a99b7e41ab9e02d32c6753100a2dea5017a9779637ca7130a977a95730ac1f0e94b8813aa30abad4706d95bece76775b64d7969a4dc2f2e5c483768b2e8e3ca4eadca1bae00413c8a285612ab2010c000000eaf3661e56b8cec97c193a3ad4e3d5f8cb37d705a1c174c978b416d7de308117dd50ff24ec61c520e41613735160802fa2152243a6a4d5a639a236b68ab731b7b9bea06a030ae060a865135ee66e011e000001027c75a5e4f11e783325731c111a76d945df2f5614291c703b67dcfa2c30917b41386bf28e1a947006a1ecafcf6e6fcb0f59214095d78c070e75feeaf63b9f12b71aa2daf423f4bb5cd47b1c1ee4010400000104ff1afc8929aa90902f74f8b84959f56f53bf85e8274d590d3793118c3082b15f8072faec35371f7b62f5ef89a67de7504aff13f1a6b3928da68f276ee2b38a7e1a0697dfc2eb8e418b8ac3d7c6011b00000105ab5699c9f8fe76ddf1926a37c5f6b3e51be4eeb193a8eb2d4c28504e30a1ce4ac97fdfffd7eaa24438995b6c9e47309c2170aff3521fa1bd3da88eaf651d4f6a66918ec46cf9789562160c251c01070000010a27199898d02e56af922c456e32c4a919c21c33816cbedeba92630dc630a2a6d644970fd77c8ac18fcd70530c956686f7e97ac99eb155232df3b65467fac075bf22d480eb18cb723dc43d056cd5011d00000139d670e3c5a70b07b89fa3ee670b7ba3211c8c61ba8b1cb07d0039861e3081038507c58da0174ca63f45e8fa7eeb1c1529883ba24046ca56948de5172fd0e86f3b50d3ee4795a1684aa95b305be60117fc001109c7fc001109ca01fc001108aafb020c00850daffb0c2c6d85e766cd1540ab6384ef345187201df1fce9f6392abb152f00002000850daffb0c2c6d85e766cd1540ab6384ef345187201df1fce9f6392abb152f2030fcd315cee833f41272d6285560c7e738c6c0b267061d1d8e3ee7387221a09101ab35421915e3ea320ee07071957cf4cd0ecd8a0100000000005fb3bd75fb752ffc000977ff0001fc0009785300d36a190c0296d43164e19fa84c5e07b099800160b278c771d9cadb83d08cbd822125e04bf704f547b14cd2568f910b8f00de48144592d8ec9dbc809130027b568db397773d473e1e7c5a06af5254ea184be9e0e648f96969c662fb10eb6d559fcfc9ddc7ab8649e360d7db6e59000000000139ef5468acdc98c786a23397a0abc167110f46bf7a33cba29de48f7597cded0000200139ef5468acdc98c786a23397a0abc167110f46bf7a33cba29de48f7597cded20edcd97758fe49da2cb337abf460f1167c1aba09733a286c798dcac6854ef39010014315246edc109d76d15bcc5e24da55d453931860000000000ae22e971fb4e1ffc000cf03e01fc000cf13601fc000cf6cb00fad60b7fee893ef0b8a4602a2250ffdedaad6dd3ce7f101b7f075273c892063b1b8571311737a5767f95c0f808aff27883260bfaf9cfe2b84519a6b2300d4b5e1f48d7a77746676f09e2b995389d0f1c18601a6f909a4b542fccce87d9f5f30695d078a9181e142602d2e93f8f0000000001bbb58bd974fb622e39f7cf717d8942e210a84534ef9561087339e79181299200002001bbb58bd974fb622e39f7cf717d8942e210a84534ef9561087339e79181299220a3262f49c21c338fda802a6ac34fe12156d45e83bfc153b96d1631eb8b7c8ba300d5ce05217d6eb331ee3567e65e0229b5ea0d20510000000000235acda9fb4e1ffc000bb3b40001fc000bc76b0026a40a8e5da5d14302d09c58ac9ace45b54b1c5a26a40a8e5da5d14302d09c58ac9ace45b54b1c5a1ec5c66e9789c655ae068d35088b4073345fe0b030048a9403592bfa7ff82749de976c5e67a36c9d6b00a6665ae7281ec87572cd4643f15e78daa4cc251d5f2dd4611e37da0000000001f023a48ba1d046f980800d8c39b239e21d04855876700421f36e716a91f9fa00002001f023a48ba1d046f980800d8c39b239e21d04855876700421f36e716a91f9fa2026da1ea7d012875ece7ceb8e7b0f0beeb31c79a0ce9d97a2da25a2a6a7c5277b0008d98f95a7cf2eb4acf392bd81733e94c3f61dea000000000036bcc146fb4e1ffc0006567a0001fc000bd99b00b8fc46281e0f858dca3ba911af267d0ba2145249b8fc46281e0f858dca3ba911af267d0ba21452491ec5c66e9789c655ae068d35088b4073345fe0b0308f2ad27c0cb7b64b6e1aa5205f78e466b70ef61c6d529202c7b7d8ca9450d08d46234fc8aed1bb6594525d300ee931cd00000000021d46a532f0610618aa12d1dca47921623ec9db0b6397b90abe63967551bb3e000020021d46a532f0610618aa12d1dca47921623ec9db0b6397b90abe63967551bb3e20d83d93971aabeb80314062415c801838c3476d30e88a185a8fc621f45cd3c780009fb125d219bc182a771e7f3b7a910fd2c0cb5c0f000000000047c6dc84fb4e1ffc000722600001fc000722ab0057124732477195239cee3a968c4923f5f8adb96157124732477195239cee3a968c4923f5f8adb961c2610f8892172b3d1cb171d0c9bae78576b38379301135af6f4c73cd6f45513a9bdbf919fc9dcf76b18c0a3256b4aee0ed48360fa88637cd113502e4f6027232c2ed5de3b8000000000264e34848ae0fffb92a5f0fb446468fcd4c18014f66212529f2a3c585709b1a0000200264e34848ae0fffb92a5f0fb446468fcd4c18014f66212529f2a3c585709b1a206cac8d4777288a5504b95c30030aab85079cbbb9dbc106b0817459c66ee4f745015b5de31b03ba63480ddd09689f9eb5a33bdb78d4000000000012eca4cbfb4e1ffc000bb3b40001fc000bd233009260f93ba7145509852239781f4f83e02fe7d3ba9260f93ba7145509852239781f4f83e02fe7d3ba1ec5c66e9789c655ae068d35088b4073345fe0b0309532b2b80bbf0241d4e35a803eee7a70a1f6c016be57daa0602d180b7969409e8518d860ae8b9c403a36dfc821fbc12d00000000037db07b953e2196d659075376e7ba9d85baebed5c49577a898c0ace2515c1ca000020037db07b953e2196d659075376e7ba9d85baebed5c49577a898c0ace2515c1ca20661dc5aa428875848e4d049e053010747c592204575036a2505345b34dd3e0bb006cae25f986f4a1e14498c3f5a8517606a0b2b8da000000000080c763bffb4e1ffb5f7e0001fc00011b13008fa9e72582f9dc7882e0e40c932d98d3026765918fa9e72582f9dc7882e0e40c932d98d3026765916cae25f986f4a1e14498c3f5a8517606a0b2b8da308f3afb0dbbfec8610efdb4089f1b163e7f55325f6c0503470e8d49ecf439c848ff9448749e0a383980824994aa5dc50d000000000428147f6fe14b66e31c953141e884b5f7075adeea7bb8d1ec85297e594dd8b10000200428147f6fe14b66e31c953141e884b5f7075adeea7bb8d1ec85297e594dd8b120d2fa36682b5c4f47ac2f5b75ad137997110f677329e8b66cfccd06df324ad897010e421caec046e5b6106f222d32d987b094441a6c000000000040b0c6a1fb4e1ffc0010ddf70001fc0010de2b0022e16c08c8f80616d040b0dc6cc6ec9bc04b467aa2c6189093918db0942b8ad5c215989cef4d367cf440eb4f521312677cf98771dc52789eb9039fc3308510cbaaeb8d82f2cf1fe1c6e6d3e7fe3d9e6ef58a5cf1c135a0d39194c457fbc8921dbcda07fce72e6aef5b54f9b06000000000044b879c7014a715eb1bd98c79e6137f45011a0cfe3d21b24edee3c1650eabd9000020044b879c7014a715eb1bd98c79e6137f45011a0cfe3d21b24edee3c1650eabd920a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e182c84bc3be703bce7915fd9e65780589f11d9e708000000000023a59c9ffb4e1ffc000ccadd000000cc93037f5cdf14ebd273fc3d4999b9cdf81865d9cc93037f5cdf14ebd273fc3d4999b9cdf81865d964f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d730002a2e19ac4b986e20f55ddb19cdfa69cbd5f76c5e2d66ac6d9c8418aa1f0836e61b643bf48eeb004ccf3f3f0f03b82a00000000045678f95d95679868cc84d96299a0b58e123e9c94088e10ae9fb54ec93bf20a000020045678f95d95679868cc84d96299a0b58e123e9c94088e10ae9fb54ec93bf20a200af23bc94eb59fae108e08949c3e128eb5a09962d984cc689867955df978560401457e250622793189bce9372839a4be7c32717f42412000000045454445fb07cffc0010644801fc0010645001fc001064630013cfc3d991d28803909680da446febc9d5b51c74542a58cb756c3edab85a715297c77ff4e02c9bcf42b5c40299408be68d22cca757ef58cf74f77c9f3085a8e547858c3772041317eac7dcd53f61fca75a5595870b44081a6bb83e78d28c397222c3c2b3015e651e163f62880b000000000569ce8b1a5fddf85850b5415b0435c46e198a8f146b1344bd618c8fc6e9e5410000200569ce8b1a5fddf85850b5415b0435c46e198a8f146b1344bd618c8fc6e9e54120027869aab3935227b4fb89499f881af9bc48c20157d1d897866e21eb4b1c3a210168688f2bafcec3f41d3c087722fc60e45a7dc96700000000010000000000000000000000000000000000fc0001653b01fc0001653c01fc00022f9b007dbc4d6ed0c5a83f528d03638e7fd3ff633a8e4d5a3086c1c6e57c19d3613870421059d308d5b16fd7c588a531c364e9462b46397e5dca10aa10dd9d300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005b687978344fa2433b2aa99d41f643e2d8581a789cdc23084889ceca5244ea800012005b687978344fa2433b2aa99d41f643e2d8581a789cdc23084889ceca5244ea820593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c093de7795dfedb896cb65547535ed92f27489d8df3000000000034187ca2fb4e1ffc000cf99e000000ec83a5f23ec17737f590153eb7eed16f7b2f1327ec83a5f23ec17737f590153eb7eed16f7b2f1327c69a0bda7daaae481be8def95e5f347a1d00a4b43080f8efb42f65ed9650078785be5d13e6e90eb9df87a99261d4de34df2b4b79a9c9b8c5e1aec7ac068ebef14636ceac4c00018feb00404d6f765856c95e587b2523a365bc725801fb8f3001fb05a30631c61e2ebf3d2f3b5022022b304492e935dfa25f9f52d13a45b448a61dea4d0000200631c61e2ebf3d2f3b5022022b304492e935dfa25f9f52d13a45b448a61dea4d2057468a144f4909b986f268cb90e353e7ab55b2c5ae55718362760a3afcb2f7e4002c89477d74bbf943461baf67ad023440a6c585ba000000000074cbc507fb4e1ffc0002d62e0001fc0002d7d400383f1034f0693df2fc8b166d242b00917b7fec07383f1034f0693df2fc8b166d242b00917b7fec072c89477d74bbf943461baf67ad023440a6c585ba30186053ffd90c84db8fb369e1178492b3a0a3941d33c43cd84b839d92668203b6501c786486083eff2b229cec3e0a190d00000000063b57f59d1ff9847f08a7f06d14a5dde1686cb43b6269e2500b2445f83aea7d000020063b57f59d1ff9847f08a7f06d14a5dde1686cb43b6269e2500b2445f83aea7d20112c24c30b2452394fb6ab5c0f9102813f19bc4e47066079329c150b567bfcd3019e735807e679a83188b4ec1b3b65192c62d4bf0000000000002d4dde3cfb4e1ffc000615a50001fc000615fb00766423d2a57121314b7b8dbea06fb83e5bb32d57555ac4d7829d25f1fb6c3abb84a180f5cf746f3e9e735807e679a83188b4ec1b3b65192c62d4bf00300c1c54b5377e920076f2fec26824a5d15ff6144dc106185a614e60fd9722d7577609ae202168a02a50ec45e01f5b7e6b0000000006a45723cb72c6dac0d839223ffb9a9ebba95d257a92537dcb7baada7fa744b300002006a45723cb72c6dac0d839223ffb9a9ebba95d257a92537dcb7baada7fa744b320a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e40841087a740cb6221d73791c04f925366d62815ad0000000000235ac1a9fb4e1ffc000ccadd000000eee87111a02be65095125160059b010ac7ca3d30eee87111a02be65095125160059b010ac7ca3d3064f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d7300e9855b2ee991f988e446b60dcd637f33a782baf1e755785ca058f0398133bf3a95e4e77d4168c13c47d7e3fb1e3ecfc0000000006ae5ed69b8a8eee0cd37f7b642989834cd1e139d1aa9de23db9a627c2fb95ad00002006ae5ed69b8a8eee0cd37f7b642989834cd1e139d1aa9de23db9a627c2fb95ad20ef3191fca4f21577e7acf2af43a36ad7f2fc0112c86ecc24e9985136201cf8b100a84773e6457d1e33d424b397108e9f462aed85cf000000000034287e22fb4e1ffc000bb3b40001fc000bc76b003db48f21a053984465132097e8e9e8b049a3d0133db48f21a053984465132097e8e9e8b049a3d0131ec5c66e9789c655ae068d35088b4073345fe0b03019bfb0fe221451734fa025e4c778fce35e56f89a1595df9cb6c0f94b76deafc6ec438c83834c9e9cf3363ee48d749c23000000000742f64ec887a0ca73a4bfbce78eb34845cee638ab574921ca260f8e218f34d10000200742f64ec887a0ca73a4bfbce78eb34845cee638ab574921ca260f8e218f34d1209602ae8d8c7e8d90259c444837e3f7bb39a5e6b4f1b2cc2b963fd42cd6b23d6f018125767a2e37003a592c97e8c4522269989e236900000000004d173304fb4e1ffc000ca6e001fc000cb48f01fc000cb5a30071a28ebfc5b60e77b6e5b853f8e0e47dfd21bb719fadaadbe9448ec9a703912e80e3b90f36519de2b802ee81026bdd6abe5b6296b993c8b4c02cbd153012271e7f58e6f7d3e2b7bf724729808642a16369b4ad22de438ed38df62b415a92bdcbe7923a858532eeedb44bf12c120000000007d22e8dadd5aa686a7b3bf833eb9bdddf4aad71a79992cbb99bf52f1e42609c00002007d22e8dadd5aa686a7b3bf833eb9bdddf4aad71a79992cbb99bf52f1e42609c204dea6406996a98efea88a66bddbe7f9568093185b08c865b1b664ae0e594c7be09eaeb400fc58666b81179de7c181cea9c63ba55f400000000010000000000000000000000000000000000fc000cf6350001fc000cf8890086a16b7ebc0c836151f6fcd1d21594cd050180bc86a16b7ebc0c836151f6fcd1d21594cd050180bcc69a0bda7daaae481be8def95e5f347a1d00a4b430000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000867e1018f1de184690af3586fc3b4e17cf61614cd926532cc13f9ecf12445230000200867e1018f1de184690af3586fc3b4e17cf61614cd926532cc13f9ecf124452320ba2a81e3cc15c2f44ba26ed842c034219c7070a07e03ad29f6177bf1afa0f3bb0171cc985fc2a69592a7be596af81beded7b914ad00000000000a516d595fb4e1ffc00025b4601fc000266ac01fc00040524006de6137f220482eab495340caf21f19261b1e8416de6137f220482eab495340caf21f19261b1e84186cf2c5c943a6d1d8364fc87e8d859f86de1524030881cec3eab18eaeb916d3f234fae24363b68faa705f51a6efb06f83adef70f73fe28ee70bf4c8300ec4f77f017dbf7f00000000009214af325b2129b52873d9e42fc94ac127aa14da17b1e579d0bee746739136c00002009214af325b2129b52873d9e42fc94ac127aa14da17b1e579d0bee746739136c20aeb90c01cdc9753256874b7e3c8dcd88388b4f5a180608b6a84fb4b5304ea69f0091e45b373304666fd45136542848ca9264f1be72000000000036d4e686fb4e1ffc000bb3b40001fc000bce5b0075400fca445584e71127ad1393fd82a37a82b60a75400fca445584e71127ad1393fd82a37a82b60a1ec5c66e9789c655ae068d35088b4073345fe0b0308d42f142045c5ab515ccc12f2ebbb43f84c822cdd8f98eb5e707d3b334c45018e40b1e2701fcd42ee1189bba2d1d8894000000000ae71d42a6b2956f22a11d20e12dbe309a20fec575aa6023b983fe1b8976ac530000200ae71d42a6b2956f22a11d20e12dbe309a20fec575aa6023b983fe1b8976ac5320eb475a0049470e4629de778010cfc0b305e70d7c5ff6e6731398e26b8fa9ff98018caf465181f5759bf9aa46aa56d8acc5666e460100000000000d3be7c5fb2715fc0003a9520001fc0003a9d300b0bd96751e06b5f3f3bb00dbbeab1576fc941f5fb0bd96751e06b5f3f3bb00dbbeab1576fc941f5f0af0fa3c6b4cfb31f4667e98c4441ec4a72c635e301438959163472114ebd0f4e72e984527894a871063cefbc8cc492593a7afbf4214538c0618ff8477590f40a3b2155aee000000000b4b33aadb8095af383a8c9c5e63750b8ef4abb5d9c091360d788cf18267fe9e0000200b4b33aadb8095af383a8c9c5e63750b8ef4abb5d9c091360d788cf18267fe9e2032048e6d7e2751d4029bfddd77d06ea72c07fffb2d2a67b73ac1cc499fd10cf9010363c23a16386411774051c4dcfd52af186bfe1e000000000091efeb11fb4e1ffc000153460001fc000241bb009e1a38143b4dffb85126ea5a1d78f957327ddde69e1a38143b4dffb85126ea5a1d78f957327ddde62588a17ab3f917f19afeb8c32fa7c486ab4105a33011d05fff5f406fd207bc8984188894b6bbd32098e58244136519a51c183c70db3d713a33c9a55f8d6993f644fb34ff2d000000000b53cea62f79dbd8b43ef803b9eb1d47a1dec3611f460dba83ba9dc32483f9c60000200b53cea62f79dbd8b43ef803b9eb1d47a1dec3611f460dba83ba9dc32483f9c620eb2272deb86efc72e1f06244693d51f169c565fd32bf3d84125ce3f6b5df327000a1d87fa55ec32af91687a166746b992beff2c41000000000005fb3fbb6fb4e1ffc0004c8340001fc00052d9300eaa8b45af937c2eefe766f3bc3ab753329aa4438eaa8b45af937c2eefe766f3bc3ab753329aa4438382477245731a85b4a1b2ca6af9e904517d07e973090403255a5c2aef92a899cf01080a78446f07e0a25fe391a81791c37eddba6e82aee9b8b86b7aa4f44129637146221c9000000000bb4178501da3646c2ac908c25dc6d890bcee788bde6b8391ccde7c6486075900000200bb4178501da3646c2ac908c25dc6d890bcee788bde6b8391ccde7c648607590204e98d6d8591e28eff43f5b3d7b8577a632df86aa7b9705eede76fdde90544c5c0141307e80a8d668b0bf3cc98a52f8d85ec8cf5ae2000000000074ca448efb4e1ffc0001fe8b0001fc0002ab7b00408fea2918afc5688ce5093b789cf08823a57ae1408fea2918afc5688ce5093b789cf08823a57ae1c0a84112810ea249524c9060518b76dbee8b86cd308ef072018a444bc1f30885a199087d2e2200ea31acc4659eb0c05cca30f83e4bd940ed27873458fb605c92556883933b000000000c807e5e4c96d56008c2e3de266027c7232d070710868e6751c2ff907a4dba970000200c807e5e4c96d56008c2e3de266027c7232d070710868e6751c2ff907a4dba972087b9b1f14a8ab17354e7504b46b9b654a7e21975f37d4bd3cdad9b6f58a1beb9010c45984a63e92bc430d99a4ecfd2e715b56b8e6a00000000006b9679d9fb4e1ffc0001939c0001fc000194ab00d3f9cdef09c63434024f1da8554f5d0ea8f2c0200df5db4ce6161b24565f0e90a154cb4e38751eebaf5f151f150e533b675c159dda83d2cd6b22c89030088f0bea4590c29e0a8657faea9d5f2e0f79cbe8f1cae3cf9111e84ecace1443ed8dfe136c539019684d9511d1bba807000000000c90176ebed8489ad010c0429751dd46ec7463589ae9023795cc49f98274f8520000200c90176ebed8489ad010c0429751dd46ec7463589ae9023795cc49f98274f852200237cc9e407352476436f36492b64e09d13d7d6acd6725965f5b368fdd55d13c01308e3fe247704d2b44831bfe98d6421c6880e5d241a0000000cebd93f0fb4e1ffc0007675301fc00076a8001fc000af0bb009ce9b000c1432c3b5ad66db07c99e97cec08e568e1668a2c23b7a257d3e1acfe926e7fb5d64b24ea022d6bcddcd53b3ce77c5afe910cad2e92c3cce4300128cccd87ee9fa75531c9d8db129ecdec0931b57d3d521d35df8af82f6972bbca75f3861faecd3b701bf4aa678b18e5017fcbdbc8ad21929157bc68c6ce50170f41bbcc5d0000000cb486a3f478e2baccb3bc755f87b241e9ffe05dd693ba92e4777dd2175b5a160000200cb486a3f478e2baccb3bc755f87b241e9ffe05dd693ba92e4777dd2175b5a1620165a5b17d27d77e492ba93d65de0ffe941b2875f75bcb3ccbae278f4a386b40c00da952b3b45775c0af85fbe2e2ab21549d86beb0a41000000010000000000000000000000000000000000fc000541050001fc0005410700864b42ecaf278c146420dd46bb2c4914328b38827200be0fcbcb2c10e968ea0b5508bc3424c9c68bda952b3b45775c0af85fbe2e2ab21549d86beb0a30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cee39f44c73a6e829fe53ee34a37ee4358ae31c2bbbae2877949ae8729276020000200cee39f44c73a6e829fe53ee34a37ee4358ae31c2bbbae2877949ae87292760220a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e1a2dd7c9995b2e03f9795f30ba18c95833f6ec3eba000000000036bd7debfb4e1ffc000ccadd000000b73068d00c048915c175450c366478f783bc455bb73068d00c048915c175450c366478f783bc455b64f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d730880f24b5e040dcbf86c3f468dd28bf45d9e41fbcd127fad56669d9afe358dcdc26e42f0f8b19997b1741dbb99c553aa6000000000d20e20e6a7ed1999b25f2dee0a53893a462e92170bc13a8b321f25c87d997280000200d20e20e6a7ed1999b25f2dee0a53893a462e92170bc13a8b321f25c87d99728202897d9875cf221b3a813bc7021e962a49338a5e0def2259b99d17e6a0ee2200d019bec606b655f5b5bbd68207755e614a79dbf4db300000000009f4145f5fb4e1ffc000129d80001fc00012a74008442f1717c0be09dd835dcf2e7383c9f1bff46c93e6504110505f16171693fa5f8582c03d7e0450a9bec606b655f5b5bbd68207755e614a79dbf4db33014bf71456476fa02cfe3de9735eaa10513e943db4576667128051f34692ce042c90cbb9dbb268d3ebf89205e5c8e2afc000000000d685a3c70d983d5668e63e80c3a756b10e19228d943fc478bcb9e2e37f97ee20000200d685a3c70d983d5668e63e80c3a756b10e19228d943fc478bcb9e2e37f97ee220cfafd40a2b9ad8fd3ace89a7a408dfe19b93696d6ced7957c2b424937849540000b1317409f33b2b7166f3e3f0651d0c0b93c0e86000000000002359990ffb4e1ffc000bb3b40001fc000bc7b3000d0cc1e8d68b1d6dc7b746ca1dae2a99a5e252760d0cc1e8d68b1d6dc7b746ca1dae2a99a5e252761ec5c66e9789c655ae068d35088b4073345fe0b030989e7cc1586c9cdc8c55cdcf122ef91481fa3d344fb313c1909d3a70e675cdc805378116b48829d287c8e27792c7ea68000000000d862fc048631f81cabda9446c5f94c8c9a559d2107db383379697381816d66a0000200d862fc048631f81cabda9446c5f94c8c9a559d2107db383379697381816d66a20818115fe0e0e7d78b05f07f774480a6e1e7cc609f071e3aa4d7ce41ba05a7a5e01eae7576cf57e066d9a46c1fafd95b339698687ff000000000074cbcc78fb4e1ffc00044ea30001fc0004c97300a86191b01824b41f452f494a6d62026fcfc373f7a86191b01824b41f452f494a6d62026fcfc373f7eae7576cf57e066d9a46c1fafd95b339698687ff30028f3d9ff027351da67047d78254333d5430c022f800ce5530835d1f048721a82d87bfe959b74aa447908e3c3cacb63a000000000e5ed7d2e33f2e0b221648c3f99735afd6762270ff6a35978df389a7f82976d90000200e5ed7d2e33f2e0b221648c3f99735afd6762270ff6a35978df389a7f82976d920a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e6ff44b8561fe1997ac3bd7d42baa68bc1e2d22e77f000000000036d48a4bfb4e1ffc000ccadd0000007d0138cea5135b7e0d5ff96c57483eb5c155f1447d0138cea5135b7e0d5ff96c57483eb5c155f14464f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d73001f24418ec73b09b00514dba8fb18d6d8af1dc2ff93d594bf987911f3b98d659eb43286cd450b7e1ee5978b361660d73000000000e72e0c50a6516ce833427d6100a83eb6f3e0e80234e126fdacf96aa669e206c0000200e72e0c50a6516ce833427d6100a83eb6f3e0e80234e126fdacf96aa669e206c2059902572f2a755ca1892ad551bb5444b4de7be0df294e2dc7f2884940d5f21eb008c7a89bc1f8f97177251dbc8aa45a53e83f7734a0000000000ae22e970fb4e1ffc000cf03e01fc000cf16701fc000cf6e30060800eb548f8267927a424fbcc75e67aad0653bfce7f101b7f075273c892063b1b8571311737a5767f95c0f808aff27883260bfaf9cfe2b84519a6b2308d29637a7883deac9d725e72cc5a1c366ea0dea49bb61dc118d2c2afe7f0916ac7b2516a4ad4bdbe7dfe68533867a866000000000ecf23a896fc8062fc373acbe0dc218c508e3e6fb0bf6d3ac8cbb3f09edd3e4f0000200ecf23a896fc8062fc373acbe0dc218c508e3e6fb0bf6d3ac8cbb3f09edd3e4f20dda17bc4e0a6ddb04f8a833c1fe9fb3aae484bc435452fd8db27cc90d0ae2511016de8fd61834a14f28d1981f188901bca0c6150a3000000000036be1b70fb4e1ffc000bb3b40001fc000bd20300e3ffb4d81895df6f9c29b45115faa19327a44d18e3ffb4d81895df6f9c29b45115faa19327a44d181ec5c66e9789c655ae068d35088b4073345fe0b03085960dddf69493f1302342857508ae1d2f02441ce7d43336d5829fa868e80ed94d77a0008ffe76b16354067952aa5b2e000000000fbea7792604319890cf39e6afed9e0866f33c38bb56424cba1cc27ff462f9470000200fbea7792604319890cf39e6afed9e0866f33c38bb56424cba1cc27ff462f9472047f962f47fc21cba4c4256bb383cf366089eedafe639cf909831042679a7be0f01527cd9e5065a523e44a8e9135c9274a6af6fe19600000000010000000000000000000000000000000000fc0001a34c01fc0001a34d01fc0001c81900ddba67c250a9c4121d546702cc9d29f65007c855ddba67c250a9c4121d546702cc9d29f65007c8558602cef7812c9171873346962583e161da2a263b30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001123e20847f3690fdd917393ce5fe60a64e3f5900cb167ca31a605683d06e70d0000201123e20847f3690fdd917393ce5fe60a64e3f5900cb167ca31a605683d06e70d202bd1a8ceda027ded8260ba896392d67b5cce6d04f0c9c717e560b5d72335816c004551586144b293cb01564f408f51f778a92730ac00000000003695858ffb4e1ffc0006567a01fc0006c05c01fc000bd9b400309f13210e37d13d130867462ed770f7a6957d8a309f13210e37d13d130867462ed770f7a6957d8a1ec5c66e9789c655ae068d35088b4073345fe0b030154fc5a23ca644b5d085ba1fd39eb6d18e070e14a703de84dcdd54bb37746461f5db2f0c949cddd6e3b225029a0342ad00000000113f86cd2940e9638cf59e9e06e9a73aa132b73c78b8b39c28ae2544ab765979000020113f86cd2940e9638cf59e9e06e9a73aa132b73c78b8b39c28ae2544ab765979202ad2e62e05e11789b21b735f21cf420f5410c0e51b163ac218a0ce6620f5a43400d0047699d8198a6066f90ea2f04011d359289e94000000000012e76fdbfb4e1ffc000113a001fc00012e7d01fc00013fec004daf7ca1ba224384b1a8d0ec83d87513ef08b120caca93fb8cc121ec6183f5cb288779a519cff814b2334b22379811352d9988876a6e586d975e7329309273016bb92b9101798bdbaf656bb14f47120241ff9c76d2650da9e399edb4f7bde8238b260a3bd935609e15e2a7c4790000000011de79269062f95fcf9f5185e33736819af5d1f83ff06589016e7992f9a76e0400002011de79269062f95fcf9f5185e33736819af5d1f83ff06589016e7992f9a76e04203363eea84b7a41211f93a8ea4fe121740ff396ad1a8c91ffe36e350930bbc3b1003623e2c434132d7cc18a2473ef9633c9b814f8cf000000000012ec4499fb4e1ffc0006568001fc000b9be201fc000bd4a30068c9612622050d25168f8ffe4f6b6819f7e4817768c9612622050d25168f8ffe4f6b6819f7e481771ec5c66e9789c655ae068d35088b4073345fe0b03002986699f0f7767bd666ae5087aa0c128b41d2e883c46ddef6e4abe8cb7ea470a2dba2a67e93274818d75839a9e631010000000012de3ea6678dadb1db529b7fa98762160625055de2aa34e757c93c136233f4a200012012de3ea6678dadb1db529b7fa98762160625055de2aa34e757c93c136233f4a2206793cf0a4aff111f1d61a13002686c066afbfe5da974cc7dec8cb4cef736dd8000542bd8c9d87e1cdd3db777d29c35e9903b17727a4120000000d4186795fb4e1ffc0010903d0000006e52a40d2dc4dea0ae7ff2b299283de0f2798b0a12deb4ca2b5a05b6eb2ab25bb5fee75d3287b3df0d5bcbeeb459af40f97fcb4a98e9d1ed13e904c8308a3dbdeee728fdec9cea3508c19ece8d2e8330b666e25666b1766ed5f44609dc8674dab4163e8574f4adf2e936a209d501c623e2d926af5eb52dcc2b931993d3e52714511801c1161c96de3dae28cd7f20ff8c2aa7b94b866d7601fb8f3001fb05a3138195ab6034f5bb94cb48fd7d46406025e17e49f41df40efa13aa0c40cc945a000020138195ab6034f5bb94cb48fd7d46406025e17e49f41df40efa13aa0c40cc945a205a94cc400caa13fa0ef41df4497ee1256040467dfd48cb94bbf53460ab95811301dd55cf012dea9a2f7ebf0237de0b9221cbdc4026000000000023e6538efb4e1ffc0008e9e701fc0008eb4e01fc0009b06300a8f3150f40bb0cabcfae79e98faa3d9d855d9f27a8f3150f40bb0cabcfae79e98faa3d9d855d9f276da7526423ec9db134526f944a3dc9a050d347ee300d554f8bc61403a96326c47b95797ff0ca91971a73f50b9c95837b912d8f0c191a85792f7ae6106fbff7e51d50818b180000000013b50c43c05e0841efa73ed52a2e5e7fc4790bffed05733243927bca596dd7d700002013b50c43c05e0841efa73ed52a2e5e7fc4790bffed05733243927bca596dd7d720b2a32448a7b0ce9868b350e12c6d0bc2ac0869659c31c8e3b1408ec253b6678e00d2962bb5abd70b77f3f33e3ec87f9684c0a0688b000000000036ca6038fb4e1ffc000bb3b40001fc000bcbaa0088b9b93ab35e81bf4152890bd22abfee38fe60fb88b9b93ab35e81bf4152890bd22abfee38fe60fb1ec5c66e9789c655ae068d35088b4073345fe0b030199cca14db47c035d175e38902dc1e3a25d52bc4ca982e4d6aa380337ab683c941842d01e436f66a746c1da20168da9600000000143dcd6a6b7684fde01e88a10e5d65de9a29244c5ecd586d14a342657025f113000120143dcd6a6b7684fde01e88a10e5d65de9a29244c5ecd586d14a342657025f11320593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c13838ddf0c05bbc0edebee7e368f4dc6306d524af2000000000023a417f5fb4e1ffc000cf99e0000007395853c0be5fb0f0348aff8128979368f52b0ee7395853c0be5fb0f0348aff8128979368f52b0eec69a0bda7daaae481be8def95e5f347a1d00a4b430b928fa4e127214ccb2b5de1660b5e371d2f3c9845077bc3900fc6aabe82ddd2e61530be3765cea15752e30fc761ab7300001b5f25f8f70cf8d05c2d2970bdf186c994431d84e01fb8f3001fb05a314bd7ee89d452d76d524dbfc31b6f2526d7c904a8d7bc1cc70d9e3e0b3d47cce00002014bd7ee89d452d76d524dbfc31b6f2526d7c904a8d7bc1cc70d9e3e0b3d47cce20a1e78087eb631164b217b6efe4fbd23722765c2ddcab903537722d183b12610a00a444ea8d94ff116c8c8363a70aac7c27a224da9e000000000022de350dfb4e1ffc000bb3b40001fc000bcbaa00fad0b3a1008363b74993501effde3aa3760ab6e4fad0b3a1008363b74993501effde3aa3760ab6e41ec5c66e9789c655ae068d35088b4073345fe0b03017288f1886c1f8dcf1d1ca73d4586fc143b1a8abd1f438a3f592b17f35f942de3ca9acc93f18cb3f4ba82b12d6313cc20000000014f2f481ca295a5bdb3e3d7f50ff87f205230609c53989da809420b874a17f3400002014f2f481ca295a5bdb3e3d7f50ff87f205230609c53989da809420b874a17f3420d8c62e2deee0738b5f0f896655ea8acc3f8c0cdb486831d94cf221a13caad545010f3771e69d7faf4ef340696fe5074743a262a6c900000000009f59898ffb4e1ffbc4230001fc0001950c009b5722d68e5dae3988ab71e01497235c79f96196a2b7623bf2c1186d629fd3234b1d058a1ae5b372b2334b22379811352d9988876a6e586d975e7329300871c91beabf5c3b98cdb1009763d03f62550e676d20b54c3fde7e50ba97e54b1cd7bf83909932697fba7627a8e583e50000000015d1b166ff3603d1a583f028e9a0b5334a48db7f3272ea2e4d101306e353f74800002015d1b166ff3603d1a583f028e9a0b5334a48db7f3272ea2e4d101306e353f748208e8e515f7025352e7c608479e413beacf0d95cbb964b47e4a98fd27b6b6b628a5be2e173478997f5d3a3289c84783714de82779cd10000000000369ad3f2fb65a6fc0005e6990001fc0006573c006b78d97d6d777cdadb430c72745d53aa169eed8f6b78d97d6d777cdadb430c72745d53aa169eed8fe2e173478997f5d3a3289c84783714de82779cd13018e4c1013002f690ead979628cecef981034bf9277813035637c376ce9dd04b1b379c4abd45bc5ea969a894fa0d0ebc200000000160120d0aa01ae90e2abb2791a313af326274536f930c95e393959598f29c636000020160120d0aa01ae90e2abb2791a313af326274536f930c95e393959598f29c63620a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e192d7ae4aac5e298584fc2e2eddcf2522ac3b8e3b5000000000036cabeb5fb4e1ffc000ccadd000000ae2c14ab7113b1aea921177e509bc59048556b97ae2c14ab7113b1aea921177e509bc59048556b9764f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d730066d57a6451b7800c1c2a6c6e04fe73ec2e1c95e492bacae760ad2f79ca3c30727ec9bf0daea43c08ff1ad6c2cf07612000000001645a3ebdeff58bb478421fe8e33119d10f22f238c9270a1e80ad46fcaa188a40000201645a3ebdeff58bb478421fe8e33119d10f22f238c9270a1e80ad46fcaa188a4207bb3153777f087f2d3c88debb4372f695aed7e3dfd3efca720e8cf4ef14cfd3e0079e8a0e8b5ad86975702bbd7f192c9cac1104292000000000068f8872cfb4e1ffc000628210001fc00062e1300dec4f1bdf91c23a8ed56738a32f2795855bc9827dec4f1bdf91c23a8ed56738a32f2795855bc98270e5c35f6bd12cc355ab5cf466721bb948e46afb9300a5c47983c44aa99ce5f04b32cfbdff42e7f92b1410558559dcbff3ca8aacc3c2fcaf05db6f021a9f335ba05b9af4c5200000000164730f2cb1a5e6660e77d03c2a4fbf4e9dd23a0798fa7697bcd0aae145ec3b0000020164730f2cb1a5e6660e77d03c2a4fbf4e9dd23a0798fa7697bcd0aae145ec3b0200e1d20e176856da05c1af552bb3d15182d45e15962bbba97702537dfaa8b51b00179f83ea215fcf6ad17a7d147199dca75723dacb600000000005350e2ebfb4e1ffc0006b25b01fc000723fa01fc00074c4b00ed358f1398a3cf37e1b3131e7c492161d6892789d593063ca9a226192be390d6841d9fc28f33818c9602f50d8a498a04e95c35af3c2545ffb074865030874a5fe9d0a2d7ec3ce741fa441e2f9a2f1726fbd2d09a000a6dd4828bd4951a82b0bef934716a40d0ff36e4641f9378000000001659e06c825212c9b11325760a18f6ea06194ec4efd603f03d8704f23d818a6f0000201659e06c825212c9b11325760a18f6ea06194ec4efd603f03d8704f23d818a6f206f8a813df204873df003d6efc44e1906eaf6180a762513b1c91252826ce0591601c274b44875713f1f7107b98c82ec14a3738e36d041300000010000000000000000000000000000000000fb36460001fb364b01140b2fea5ae1aa7e6b8ee68a11d2727663397163595d9f40d00a7ea5cca2502a1c5bc47706688c42c0ee80d8e78d59877e5ca6fa6d071f2bbf3037e6300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000017013c34733cdafc4feb7f317587cbb891b1027ded099e2dc2e8e1da05ad0f4200002017013c34733cdafc4feb7f317587cbb891b1027ded099e2dc2e8e1da05ad0f42208e8e515f7025352e7c608479e413beacf0d95cbb964b47e4a98fd27b6b6b628a21492077ea3f2aae501b0dfa814c61c5626c09a614000000000034d41347fb65bafc0005e6990001fc0006576c005caf3605e05011b3abef72e467ab5334e74d68635caf3605e05011b3abef72e467ab5334e74d6863492077ea3f2aae501b0dfa814c61c5626c09a61430836747d419d09200e404aa3500fc5d51f044fc01fd1a9f452324c8c14ab90ccd75887b6bae1599cdd458e738a53587f20000000017454490f2e0d86c39e8d0981b1d1b67354a96915a5866c527ba06fa08b43dcd00002017454490f2e0d86c39e8d0981b1d1b67354a96915a5866c527ba06fa08b43dcd2059e4a4ffb2097f50e8636da1d9fb7b58400563bb19ffe74555b42f7581cc2b74006fb36a0176a614d53ec1402019421234316f9d83000000000036b8f747fb4e1ffc000bb3b40001fc000bcbaa00babd4d5499f8186f8b73cba064eb0cfc4deff4f6babd4d5499f8186f8b73cba064eb0cfc4deff4f61ec5c66e9789c655ae068d35088b4073345fe0b0308fd6de82030e06682e2e65de0fe7efe2edde83f5f96c3446716278d240e0bffb9bf33df3d64d36b9cc6649da7bb0b41b00000000188b4f3700c029d93de43a0e865b3e2e800c3bc67718f8d213dd111a9e401cc2000020188b4f3700c029d93de43a0e865b3e2e800c3bc67718f8d213dd111a9e401cc22068cae611582070c7859ca4ff173baee189eae61bcdd27be131df62a3a630d34901d13ab9ef967f44ff97748303c21e421a7f80974a0000000000761f230dfb4e21fc0003c37c0001fc00044d830039935d16dd5f12eb27272a4190608370e212224fa7755e80caba03e54606c89f955d1d4b9b85d91cdbfeb2a85d70b0a32d9cbc6f4b8f1ba6e375065d30831193814d5cddb0268d276281ff7356b9cbe560bbcb6c9c55f12a53b0dfdb60ed5570c9c4bdd39d8a0728dfb2b0596f000000001910a0aa60c10475397dfc5507a1d765070f96efa15e7a4c6ee559461b23ec8d0000201910a0aa60c10475397dfc5507a1d765070f96efa15e7a4c6ee559461b23ec8d201cee1e4ff907fed96b4079561103d57bda553019cca81d84d0f749c60a5da59c0170f9622bdffd2cf2aa9d2e54ca97ae74ff19b54200000000005350cc76fb4e1ffc000ba06001fc000bbb2d01fc000bbb6b00a2e7118000386185b278ec3d5304db462f23cc55a2e7118000386185b278ec3d5304db462f23cc5590cc3f0be1a150f59168adb0236005438c282f9d3090a2a532b28ceb661521902ada94853f1b90c1a7d13d8ce8a40ebec6c7a62a4e22fe5c1019e278750fc93f6808f410d3000000001a5889046c1a29a03a8a40bbe26da1539d1abf53f9b846857c7fede4d5e3926b0000201a5889046c1a29a03a8a40bbe26da1539d1abf53f9b846857c7fede4d5e3926b20a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e70f6e92e766ee782976b3a25db2143060fd0e69c5d000000000036c8dc69fb4e1ffc000ccadd0001fc0011055b00a5c9f61e9276d9a8471b75beae8d0b91b5b1cbb9a5c9f61e9276d9a8471b75beae8d0b91b5b1cbb964f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d7300406e459bfd155c81f9103a1fe076f1261ee7513275d744c133c5d5dfa956b1449f173bd110bbc03673f376593f32a27000000001b34fcc8306280449bae2eda2361fd372380b9b630b272fc44f55105c58f16110000201b34fcc8306280449bae2eda2361fd372380b9b630b272fc44f55105c58f161120eb748acc6851ad16efe38875924bc04b4c3451ac244e1c979217ecc42b2f90460075fb7f518ebf31fc70855f607f7a092e8bef53cf000000000036cb869dfb4e1ffc000656a80001fc00066e7c00e922c71d669bf4aa1fe543345d67d0be170b91eae922c71d669bf4aa1fe543345d67d0be170b91ea1ec5c66e9789c655ae068d35088b4073345fe0b0301622ef0d7145ce02babddc8762f170f46d5d55c151218ffc12aab3ea9faf90dc97bf158a0fe37a3d8c1fc416bf01bffd000000001b8466759e68ad97c55c8c96a24a060a839baf8a014a7ec897ab6fee410e66e60000201b8466759e68ad97c55c8c96a24a060a839baf8a014a7ec897ab6fee410e66e620e6660e41ee6fab97c87e4a018aaf9b830a064aa2968c5cc597ad689e7566841b0138c25763a87e0036a3f5dab27aca1c85bea508e8412000000023f70440fb4e1ffc00081f780001fc00087abb0046d82dfecb82e98abd5b694ffa54558168fa593c46d82dfecb82e98abd5b694ffa54558168fa593c6ba9df01752f7015bb150fb432f598a91f8b22e3300b0a6390cd90308c8b7adc4374fee6d4c1d0f467d543dec6e306922e7e78d06ddff70e6adf6b2410cdaaf0d7fbab39ba000000001ba9b400a99c8ab19e2681db0e868814aa273e8eaa13615979a14c50bbd53f4c0001201ba9b400a99c8ab19e2681db0e868814aa273e8eaa13615979a14c50bbd53f4c204c3fd5bb504ca179596113aa8e3e27aa1488860edb81269eb18a9ca900b4a91b017c706d1b78fadb609fd92ff5929901a706c55877000000000058162c0bfb08aefc000cf9830001fc000cf99b00f74034f58c080be74bec51165c5ffe60ed1a615f96375e263814e1d54fc3297fe893dfb5a9c1a9eb6443411c39e405d2520567d4f6b041c5c550086230b006ed30975f322c830001d1b3c2e2f14a4ef35445431356f1c5b93c2eedd9c7ea24c4429d27d45f2fd701733ffd65540001f2dbd9b0a1f541a7c44d34a58674d0262f5feca501fb592501fb59261be5730f3876206a58161fa0db37e54389324519b2ffbe53a18910d63e5f74db0000201be5730f3876206a58161fa0db37e54389324519b2ffbe53a18910d63e5f74db2075fc3c877547021a42f8a7f69212d570e4b1c261d7ccbd13a46a0e4cd6661de000d1297438fe58cf5cfbba6dae5cca982c28d8e1460000000000235b74e0fb4e1ffc000bb3b40001fc000bce4300dbf20e7b2d642daebba0567c14cda3d4363ba372dbf20e7b2d642daebba0567c14cda3d4363ba3721ec5c66e9789c655ae068d35088b4073345fe0b0300c03388550cdb5148a63bd3f4ba937b05845748773dfd1adf509ab94d5c525e57f8654b723abadd85d2b650f14a8b9cd000000001bf9d1c02dd94bf4784aa6c1b959942ef6acf0ab1a8579be428b01b5fb87bc8a0000201bf9d1c02dd94bf4784aa6c1b959942ef6acf0ab1a8579be428b01b5fb87bc8a20a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e0b14169d588590a243f1ca0618dd35474b06d08daf000000000032703a72fb4e1ffc000ccadd01fc00107aeb01fc00107b130083564ef2fc85085dc7f2a155a64fb5d14d89dadc83564ef2fc85085dc7f2a155a64fb5d14d89dadc64f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d73014e81203caa5c0cc305b5e0f3ae7a388b974a629358e4e83e50a25b2c2a387e3d114c7c82e2b23c25b65585220e63c99000000001c692349b501682aa983907516959bd6a0148c23ff9b8cbd178e1e07fd9275660000201c692349b501682aa983907516959bd6a0148c23ff9b8cbd178e1e07fd92756620a3ff4c5428133a31449bde462aabfbc9c65ac5044e832ca0900819c8a7feb17d01f32dc6faea0264ec91432ffc25183c63b695ab1f00000000002cf298cbfb4e1ffc000b16820001fc000b17d3000bdc4306178f7c576e5904ed9c0643f2faad4ae3a164232c5ce6f1a1448084d628145eedb09f01472567856cdf62ed7325c44bd7b7557e1acb330a63300923d28fcb1fb8b90bf8281f2f50b6a109f2f5b17a4e1653e193ae58980a03b3538ceb82c6b4e1e986ad40d08c63e330000000001ce233bc4e4b8104def542c9ca2929cc95b42a3bff03ce5c3035dc04cc71bbcb0000201ce233bc4e4b8104def542c9ca2929cc95b42a3bff03ce5c3035dc04cc71bbcb20f8607030e04bafa10d798515b6877c0a599fe907b1737cd0db970c8d144e82f000307a1f9ad73350c1489d17a35ceced0d0405aae8000000000023a51841fb4e1ffc000bb3b40001fc000bce4300d5b08c823b75db3900a75e36c0504619e8a47ecbd5b08c823b75db3900a75e36c0504619e8a47ecb1ec5c66e9789c655ae068d35088b4073345fe0b030880423a2ded94f06b02b66e22219495c386733a27f1ebf1d5aea6017cfe510d6d0e0479d2a5acbf410e4d6e85d7d10f7000000001d0adeaf787ed8f6f73fa936c6313ddfa2dd33ea693a2de22bc346c1b73a4a020000201d0adeaf787ed8f6f73fa936c6313ddfa2dd33ea693a2de22bc346c1b73a4a0220a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e3c6c8d7e6bc5c0d0f84af28da5ef358d40f058ba81000000000022dcaf1dfb4e1ffc000ccadd00000068a589741e0d3d06e5aae5ae008f2a8b11426a8c68a589741e0d3d06e5aae5ae008f2a8b11426a8c64f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d7308b7c76ec03f7ae0dc9be41fb9168906ef0d0d4de74f0ad8c5cf0a30483879b5203ae5d7c6aeee5b92998444bc10f68ec000000001d808b8e69cf109e2b25bb87e40e76593d385bec2ef26e9b0672a3c69418c0f70000201d808b8e69cf109e2b25bb87e40e76593d385bec2ef26e9b0672a3c69418c0f7202fa3b3c49a569e0b5d61aeb0dce73c34d2b267de6c03f81dc4509c1ca6d3f7d300337dde5fe7ce3f75adbda925932e38c456e59e8b000000000022aada88fb4e1ffc000bb09201fc000bb20e01fc000bb2230091755d751fafdbf3c4d1e1dc94c2bc198f7b5bb591755d751fafdbf3c4d1e1dc94c2bc198f7b5bb5a683e40cf2b717576d777fd4a81660ac6c7d939c309687b4c357c8faa53e6733e83b77b94e92d2b528047e2e4cad325810b5e4856b7ffabfdf97c825d224992838d7435d75000000001f1443d9f38273f6437fe37eb34c30033fcd51c7e7f563504c8809906e711de30000201f1443d9f38273f6437fe37eb34c30033fcd51c7e7f563504c8809906e711de3209e3bd9b71a626baac323ec5a6216882496eefb8d70c6a1ef95ee01d57659aa39012ef68619350d67f5e1269aeb7d0459317ee69f3700000000010000000000000000000000000000000000fc0001a89d01fc0001a8a101fc00022899000733464b2d4975e9739512fd74cd6747495adf2f4d532ed2827d7bea5c49ac0e1cf57d6dabe11e06219c4fe7634649826ed14bb206cf90cd20d5bc1130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001f3ead0b52a6e6e289794c0e84dfe988bd88605fb987a919ea4e3956dc4791240000201f3ead0b52a6e6e289794c0e84dfe988bd88605fb987a919ea4e3956dc4791242046867d5c2d93ac83e7ad8a5079e609902a62f394b4c1858324fa459a652837f60137c49591bb612183440470cfa5065e4090d31e290000000000344820cffb4e1ffc000bdf300001fc000bf28b0048022a40c99c1a58ee5371a2cfc1079df5715aa3e1aea521fd5d9c90c17704c6a7b653c6fdd42ce8264726481a36d7c39125bf90457cd47190718d5f301641b24598bd24e49c4c2c59d027567d89f2e7315e53fabafb508e48a93b48f32525fd9dd9266b0ca4bef5d08b9605af0000000020107ec50e81880dca18178bb7e53e2d0449c0734106a607253b9af2ffea006c00012020107ec50e81880dca18178bb7e53e2d0449c0734106a607253b9af2ffea006c20593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c117663ee06b0b159308edf41150954372a730aa6a50000000000235515b3fb4e1ffc000cf99e00000004d65ec5142719f58e31f4510dda3c810a84364204d65ec5142719f58e31f4510dda3c810a843642c69a0bda7daaae481be8def95e5f347a1d00a4b430b6e979f20241cbb73de7451779e8e059d9cb75a74b72ea6862d7ac703dc2ac07d86cec39b6e8923b55fd54dbc6177c3a000135d9eb76397d05b43b5cd8da7ccfa8408bc89ab301fb8f3001fb05a3207d97711f4c60a23f5ba1a79bf4b86adceb51bdfc25ce25172c8a311147bce8000020207d97711f4c60a23f5ba1a79bf4b86adceb51bdfc25ce25172c8a311147bce820cb2fc1a392bb538ebcc5d73250eccafe08c96e6e7e209185f6e73ee8ffd84074001738f719112c8fb6fb5e9d66f9b011c24219177a000000000034286568fb4e1ffc0006568001fc000b9be201fc000bd4aa00caa5590bf043919888c4bc0c739482e84d51030dcaa5590bf043919888c4bc0c739482e84d51030d1ec5c66e9789c655ae068d35088b4073345fe0b0301956c264759bd857f9d78d04cc67e42b39e5296bb15f16d0350d741b026ac4a7fa79985eb63c487d91b7ac250dea3afd000000002344c8196ab9a4becdfb3a287a511278581d784b9afda234be289c85463219ad0000202344c8196ab9a4becdfb3a287a511278581d784b9afda234be289c85463219ad20e79944387083c27fe76eed01599c5c4921f40cff7a45e6b62624b97b748730ed005b224c407e486ad5d944af0e7344fd0dc3a20e05000000000022dc4a30fb4e1ffc0006567a0001fc000bdc0b00a988a44ae537e9365e8199cbfe84c453714bf3aaa988a44ae537e9365e8199cbfe84c453714bf3aa1ec5c66e9789c655ae068d35088b4073345fe0b0300d85038bf7b6e4365042c33610afbd181c0729f2107bb7e3e229daa870007757e1851a077e252405ff35373e780815d7000000002356f75f3f35322a81e5b8a37bf6ec59388408f8faa6468075ee5f4026ee0f930000202356f75f3f35322a81e5b8a37bf6ec59388408f8faa6468075ee5f4026ee0f932015842c095193a92bfc68c7b66dce922a9c3a119721ea0f0131727a1633bb982f01cba75a1c4d696337d08874fd92650aae0b7f8226000000000023ac3458fb4e1ffc0003844b0001fc00048ffb00dfeb04f9a4566f877926da380ff6cd983f693747e37b26efc667299ef749a8ffb5a2a64bc48c5236315fddab967ae28ddfb91ddd515c7b89bfeaf2ee3005d35fb7ea96c707d0bb6a9185f575596285d3578af73d43d2940e6ba7a39a60ad5d3a6f5df16449e4f5ba1cbd8306f60000000023dfd9ad3215287b8e08973b049a55a3024058390e1e9c338c98c967e6de38f900002023dfd9ad3215287b8e08973b049a55a3024058390e1e9c338c98c967e6de38f920b6f6b4620ced1393cbbd57400b11c84142d66c9ab6553cc5dd4b21e6add8c96801a62279c8b16cc1c8e38faadd5c7d146e67e5bf3a000000000022db3f31fb4e1ffc000b9ba201fc000ba67d01fc000bd4a30078ef25845ce006d5f5fc3be9773e2f57282f4bdb78ef25845ce006d5f5fc3be9773e2f57282f4bdb1ec5c66e9789c655ae068d35088b4073345fe0b03014e98c3260409c144f2ef15607ca1677c6eecdf723e3f7c99b25e0f561d4a315d25b702e9153524446b0a2514bb09adb0000000023f239d376d072dfcc083c6e012b1aa149a3ab66cb8bd524c2a00fd534a5d26100002023f239d376d072dfcc083c6e012b1aa149a3ab66cb8bd524c2a00fd534a5d26120a83c3da02e42ee3c9c13e27ec391c97a43f6fbb59ca6dab3086f6f6f2180565601f2b65c96c7febf32ea46461feb1b1c0d00516b6e000000000050f0182cfb4e1ffc0006d4c101fc0007015b01fc000701ab0091cf245e465930b748480cf54da8da800e8b49591516fc10404fc6199c750577dabb9f26800c86525748d29ccddd0db9317ce1f8c3f4b8ac69731c4d3094b3e11094b8781908d100194fa8b47659c2ee17720200f9fcdc2804c557d219e87eb68fb0e6db97822f1f73ab7f846d00000000246b31866af114ef8f6d7146a68bf15004c1dbcc7229accd1ad81078547b4d96000020246b31866af114ef8f6d7146a68bf15004c1dbcc7229accd1ad81078547b4d9620904bca9accaa1c0120066b43889cde3737f885679baecd956cb34caa1523842f012aec349ad1f39b61c6116b419d98d1ebfa980fa2000000000022d934eefb4e1ffc000bb3b40001fc000bce2b0057fc65161b69a4d3fadc9c4e75850d5b4ae0256757fc65161b69a4d3fadc9c4e75850d5b4ae025671ec5c66e9789c655ae068d35088b4073345fe0b03017b350c9c4d8b39af2ce0e3fd8d7cb9539a6da30533f8fa7c2aa1c4f6b976f625c6b68e86d95e79bf9c758076569c35d00000000254739a1dfbf7795267e64686dd07cd61c6f87e665efd52e15910fa29b3da3bd000020254739a1dfbf7795267e64686dd07cd61c6f87e665efd52e15910fa29b3da3bd2068d9641221273796f8fbe1d920832c88a3b5b4b95463206485182f648dd3fa670096345fddfd53f65ef43487849a6f469c9eb64136000000000047c6dc82fb4e1ffc0006f4d10001fc0006f51b00eafc007af0360da4457b92cbb8ad08650f20ea4ceafc007af0360da4457b92cbb8ad08650f20ea4c19c2c7d2ac04ffda699922b0d78957ee839ebffa3090f7f3a97069a5090c885a85aa7e8c970b5d3982718dc4394e2de8ecc2d1c38c8ef51a322e6a5e9660eb794af6c404740000000025b1e2cc3dec589720bafa5769d16437e2e5073d63df9659d05199fe22366b0900002025b1e2cc3dec589720bafa5769d16437e2e5073d63df9659d05199fe22366b0920d73d548e5f6c1b4f19114e39bf27e78530faa14c6fd4f019c589805c624556c4014e63b061493879a21b61e49607d988ce43449eed000000000012ec855ffb4e1ffc000bb3b40001fc000bce43001c544de6c1eaa3cbaa78ebceeb76f1c9d9d799941c544de6c1eaa3cbaa78ebceeb76f1c9d9d799941ec5c66e9789c655ae068d35088b4073345fe0b03083cc6e11edd346dcb19cd422faeb218e37568f66ef70656c93d6d43bbd2eb8715a99af27323d075f6b31d955ccb303e400000000262f95031d76363e3fad8c110694a8894077ca0ae98acffc94200b16cba997b4000020262f95031d76363e3fad8c110694a8894077ca0ae98acffc94200b16cba997b420abf84695101d7649a8be1488b7173bcd83a050c4d4735974b6f08c997f1fffa201feadb5e4467d54029de5820c960b2932ba61b58b000000000003e25369fb4e1ffc000607de0001fc00065754000348d6a81e71ebb94c607c7c79d9500f2d689869f98d462531cb02fdc829890da5d5f248c81f961958b2b6e9982851794782fc7102ceffef076d4c15308a50a9ec0042d293ca23c941142561632df2f182445a96d693b70079a085dc35073092d00761156f88a1f269a2d87e7f000000002695fed97527f712995a207d278a1cb7fea614effd3f6d3cacf58052af020b8c0000202695fed97527f712995a207d278a1cb7fea614effd3f6d3cacf58052af020b8c208e8e515f7025352e7c608479e413beacf0d95cbb964b47e4a98fd27b6b6b628a46ba4f939d4efc43e1a17deec2b9695271bd162d14000000000034d41347fb65a2fc0005e6990001fc0006578400c33d559a563e9c22c95585c0f556727c6c5195f4c33d559a563e9c22c95585c0f556727c6c5195f4ba4f939d4efc43e1a17deec2b9695271bd162d143091c5a9a2513c46543acad374e11f69e63df9583e74e511e619355f2cb7c1b9cd7b4c1ddf3f33c28a8c046658958c3a1000000000271b3eaea9e4fa8717b42dc04a257bf689d56e400683d608ff7cec3a34ad7115000020271b3eaea9e4fa8717b42dc04a257bf689d56e400683d608ff7cec3a34ad711520a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e428d9aaf516d9d692b3476014c6f0790a8c609991b000000000022d21a5dfb4e1ffc000ccadd0001fc0010b6cb00476fca90e883f3fa6116515e120c7e4c1b33d302476fca90e883f3fa6116515e120c7e4c1b33d30264f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d73012730062f122f937b29f69536db3ad36980b88004eadc2ca341425d432723d67e53a4f55786c54017d77c1bd1df6b31000000000274ae6ab38ea0f3b8fe726b3e52d998443ba0d77e85d88c20d179d4fecd0b96e000020274ae6ab38ea0f3b8fe726b3e52d998443ba0d77e85d88c20d179d4fecd0b96e20a096901dffaa36cab6566f3a7028c1cb81ab8906b6804a12132666cfb240301301bceb142ede41aa52eed6c38b326e7df12226e01c000000000086d1e74ffb4e1ffc000335940001fc00052b840074f9875462d0f10d60acafc3f64ca89e86e491977f0dddb29235681f498bb64f7bdcee4bee1f4c98bceb142ede41aa52eed6c38b326e7df12226e01c300db6da5d8ee9fb8925f0818df7553062bf35ec9d62114144bc395980c29fcd06b738beca63faf265d7480106fc6cceea00000000289b8c9733345bd0c9855f933d947192f566a6d6bd5ca694d3ae0b5e9d3882f6000020289b8c9733345bd0c9855f933d947192f566a6d6bd5ca694d3ae0b5e9d3882f620a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e1b2f17f1892888740eff564e5925560fedfee93f7e000000000022d254a3fb4e1ffc000ccadd0000001c6031c212e840f9756b8f08e3801cca20b38a621c6031c212e840f9756b8f08e3801cca20b38a6264f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d7300e2825781a496023c8be61f2bf352ad1094afd6e4f84c4ef331bc727bc149a6dd7e23d78944b8b047c03da44eef1c79600000000298bb1ffac5832d9bad4339c93948f449a2aaeb2d66f685836b6bdf4275b6d6d000020298bb1ffac5832d9bad4339c93948f449a2aaeb2d66f685836b6bdf4275b6d6d206d6d5b27f4bdb63658686fd6b2ae2a9a448f94939c33d4bad93258acffb18b2901dbc9cf11f6b96f87c6435430e66384b80d674c380000000000ae22e976fb4e1ffc000c225401fc000cf06901fc000cf6cb0031471f3f5be089945132a63168b2e4feb2cc5893ce7f101b7f075273c892063b1b8571311737a5767f95c0f808aff27883260bfaf9cfe2b84519a6b230925d20af1a6d0ccd3890f0aead4a05a59be22e005b6d732f855311915b351a9153b2c83d84611b2c9958f806c93f7b5f000000002ab90c655fce7462791fd57049fd3477460cf45aec3483dd8f92ac76cbb5b65f0000202ab90c655fce7462791fd57049fd3477460cf45aec3483dd8f92ac76cbb5b65f20ff005bf96c06ff60140f082130050e2c3231178769c841f5d2e7c8936c53214301491707fcd2969c5f8ece1e0102d6f8425336700100000000009fcb1514fb4e1ffc0001aa940001fc0001ab14009406f3c3f3e20632e58e419a5107a5db669cb4209406f3c3f3e20632e58e419a5107a5db669cb420491707fcd2969c5f8ece1e0102d6f842533670013006b2e598c2a16e7394cff63bb9939e8bec49849f2520f97d8de70ed9336625ea0582889be68007e93663685d03d6996b000000002ab9d8594ed6b96aad7e0d89e739e15f43540da076265f22f1f2be892b9af9ba0000202ab9d8594ed6b96aad7e0d89e739e15f43540da076265f22f1f2be892b9af9ba2031b660b28d594534ac630a8e9739ec2d87f054298223188a66f7ab813007545901653e5576338dd6a629c58b7bed6fada76b62919b00000000003ada3c2afb4e21fc0003b80f0001fc0004053b006672b178caabeecb6cbe108c960367333fd237f778a2c01c623373d2761103791484d3ad1164c06d22ee55a30f4a11a8c3fbd3eb1ec76d9ca8ff4ff73004eda2a8c31489e17463ea27c0c39473afe2c9153641028de360eee8ce213d36a14ef8f8b4f85fb2cd70815a9c1f56db000000002bcdbb54e0eba24d0a83a339436d84c916947205535f755f21cc4843ea3d2cf10000202bcdbb54e0eba24d0a83a339436d84c916947205535f755f21cc4843ea3d2cf120d7c8b2f884a83fecc4227138495333e0db8b7125f2d9a306218176604a30f48600481565d75de04c111a345dd844afde2b9a54220b000000000022dca522fb4e1ffc000bb3b40001fc000bc79c0008b5cf180aa32a061e3ad75bc37908a4ff705ce808b5cf180aa32a061e3ad75bc37908a4ff705ce81ec5c66e9789c655ae068d35088b4073345fe0b0300d450032d437d4a3ce7b62b4fcf70599c467722d2a3ec10844d4cedbe6783d39b7180fa294e7b3f819c4b4c293437770000000002bd7d5200b9a5e22d5c95c2c19923e9cff64ed36a1f736372b87d82b2383926c0000202bd7d5200b9a5e22d5c95c2c19923e9cff64ed36a1f736372b87d82b2383926c20451a8c759ac8fd8f333e230268f26808131fc02a734a1fe98b234ddbae4b1375019263a05cc87500b6bd59287c7665e0c84f210c9f000000000022dc8cccfb4e1ffc000bb3b40001fc000bd21b00eca70167cf9b64e7daa3bbefa9fdafb213f5016beca70167cf9b64e7daa3bbefa9fdafb213f5016b1ec5c66e9789c655ae068d35088b4073345fe0b0301066424f46c8c13274c1aa17df6a3fc1ca4fe80d9dac09525ae40670c5a6ca193854ef663940ddf64740fcaf7b83bac3000000002c8126dfa695f9c0da6183451834b6ada03adc05c54c72594187bbf65d8591f30000202c8126dfa695f9c0da6183451834b6ada03adc05c54c72594187bbf65d8591f32095cfedb09499fd9459f4cb839f6fc086a7ab10762181108913f996689914d050019f9db9aeabf86561085372a2ba98078afc0ef278000000000036bd713efb4e1ffc000bb3b401fc000bbd8501fc000bd21b00b2a4ee6e3d9d40899ab18ae6f737c85278d907f4b2a4ee6e3d9d40899ab18ae6f737c85278d907f41ec5c66e9789c655ae068d35088b4073345fe0b0301095623aca38c0609bf75ce889406d896b2d06763728796d1d9e154392e74e16e41716c1dae79d1e321a47ce2e4eac7a000000002cb309db9b7c22b337a7c24aca6a2d730030bef2f3a7c5f104d6c9ffd9ee64d00000202cb309db9b7c22b337a7c24aca6a2d730030bef2f3a7c5f104d6c9ffd9ee64d020d0cdca3ceae80c1da9521a82711b05c63a82a6821b2c1ba4e9d2a529f645bd61003d1eb245b39df4983715e8579b8053ae088176cc00000000007217368dfb4e1ffc000606a50001fc0006072b005871467000cb7d7144ece56406a6d0f8e97360395871467000cb7d7144ece56406a6d0f8e97360393d1eb245b39df4983715e8579b8053ae088176cc30903a0f90f0ee9ee05c0d567eaae8ca9aab5bf0d5d1e0240494f40e4bf954201e48585c5a2897ed76697b4fb95dd993f5000000002cc0a073e9fadb5cea5cc3303b8f85ed603dc6de043f0ec06edab72d886c57cd0000202cc0a073e9fadb5cea5cc3303b8f85ed603dc6de043f0ec06edab72d886c57cd20f2645684284391532fda7db234d517365631647782fcdfae42d5d7ebca78f3cc013c56bfe3279092a8afe0a282c66f1c68c6a331a100000000005fd8ae98fb4e1ffc0002ddc90001fc0002df8400c5871227ddeef90af4d9e891170c4407a5957ca0c5871227ddeef90af4d9e891170c4407a5957ca03c56bfe3279092a8afe0a282c66f1c68c6a331a1308dd3ff4dfb358ca5c5c58f5c163d73482caf44427b62751b18255a456b8edb175f887db87b3b214753045f631db58475000000002d3394ece5ebfb9e2f369fae0c663b01b978f946dfa06fe938f2c292661c94990000202d3394ece5ebfb9e2f369fae0c663b01b978f946dfa06fe938f2c292661c94992005987511f1162441ccd624fae51f48274da77bd4a6a103de7b767a963e06280e00bbae8d6f3091b51bb8bd2e948907ee11744e6616000000000050f017c7fb4e1ffc0005329d0001fc0005340c008c5f76e0794a0729c41142e619663b77948748ab8c5f76e0794a0729c41142e619663b77948748abc66ab236698c66f559ac918689cadae4c8aff0f6301260b9b40d6a39c14c5f52763ef6e98094a6d41ed35660ba24334c50b60cbf18a524aec8bd4d0203c3257e70e193fd30000000002e48651a2e9c0cb4f2fb7ab874061aa4af0cd28b59695631e6a35af3950ef6fb0001202e48651a2e9c0cb4f2fb7ab874061aa4af0cd28b59695631e6a35af3950ef6fb20593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c0101e19b30edacc8bd047a72d6b12b79b3f1b2babd0000000000369521a7fb4e1ffc000cf99e00000063f16c50b9cd1dccd8465e1802749bd00dd49a2d63f16c50b9cd1dccd8465e1802749bd00dd49a2dc69a0bda7daaae481be8def95e5f347a1d00a4b430943a88959611417f9e8ce4e664e1d9c6a839daae14f54ae8e78bc5ef6ec1524d116efca49ecd5c57dce31d90015a51ff00011ffbf1d32541dcb8f5555305295704a9ff9adc2401fb8f3001fb05a32f4bf68bcd9f4fe5171f8111a7f007f76d1298c1124b8a85174e64e057a2522d0000202f4bf68bcd9f4fe5171f8111a7f007f76d1298c1124b8a85174e64e057a2522d202c4f5235e6615104fa3709900b96bfc192e6264d8edfbc24f7af6f1d9b2508e900e5ec4a87e9bd6276f5954a87ddbae45e398bba5c00000000003694d7a1fb4e1ffc0006567a0001fc000bd99b0031e5d66a6457e3181b3dc060f5a278bb61a54aba31e5d66a6457e3181b3dc060f5a278bb61a54aba1ec5c66e9789c655ae068d35088b4073345fe0b030978c2c6ad4f75b983efe0be4ff9d9fd5c70645dfe27b4aadbb33ea857e63ae59f7907a9e65850000d968af60e264370c0000000030110b4643c2d8c7521f27ccc2a6a70579bc859087fb95facbb831b3a3d107c700012030110b4643c2d8c7521f27ccc2a6a70579bc859087fb95facbb831b3a3d107c720fbcd42341652da33e977bab8bbef42d0f053f93e9e2748f3f39881d11e28910c017798d43ef1f85193b1a0e5a7ab7853a39d27f0334060000000a6469a72fb4e1ffc000f01930001fc001046630057656569e143ae0cc0419020708c8ce5f4c776e452bfa12608d37422d52423c3a71f9574ffa8267f535e571f5fb89e31f634da8b91769ea4dd252e19308cf6a03c7a0bd8c38c1fc536a013f93afc8224cbfc79d8b0157c7080117ec9c1c60198c3fb3886ec472aeaf80bd5fffc0001c3f93922e89f4bb3869da0c18d8e30dd91019bb101fb669601fb2710302ba9134d9d734e0a76599c9cddfdd1ea2231ff6c152fd5a95c9ec38aa66d02000020302ba9134d9d734e0a76599c9cddfdd1ea2231ff6c152fd5a95c9ec38aa66d02203114c3b632de2d7ece96a92ea26b83b4ea213a9db1eb4fdfc2dcfa84e7cc500900c437a1e129915fbc02e98bca6d8e8fb8d08001c60000000000a5e33fdffb4e1ffbc40f0001fc000196140036c7c737a21e3e6227791978495ea6516da151c9cea287fadf53be3891e7d421908b9a64a5ef3147b2334b22379811352d9988876a6e586d975e732930083997ad0a7d12c5038242eb54f0aa3952ede09814c57b7392adc4db58f4070dc0b44431c20be0636a21ec238436fafb00000000306c038de5c583febcb09b55f527eaffe177acd9d118e8076f61349a305e902c000020306c038de5c583febcb09b55f527eaffe177acd9d118e8076f61349a305e902c208e8e515f7025352e7c608479e413beacf0d95cbb964b47e4a98fd27b6b6b628a0e1e7fc490e774db8c9100bd196291d79699001e24000000000034d41347fb6598fc0005e69901fc0005f6b801fc0006573c0077d7ce66a12ce0c43ee6b3b9116649dba376cbeb77d7ce66a12ce0c43ee6b3b9116649dba376cbeb1e7fc490e774db8c9100bd196291d79699001e2430052abb8468545b0593010c326d358cec47a3079a36c6f5002b2c36fb45aeaa6ef00746d0e73697fef01704d51d8704940000000030bd48a0fe09f6d72a94df8ca9d58e1c9015dc218685f17e2f711a1c8fd3c3fa00002030bd48a0fe09f6d72a94df8ca9d58e1c9015dc218685f17e2f711a1c8fd3c3fa20ade9aaa50015e14f1e50cb83348552efacd55d5f4198c837d8b6e01af95e510501bc1b78aed1c8dde1141a1880702373d656b7e7420000000000235a9f29fb4e1ffc000bb3b40001fc000bd20300941e9b03a9e4597551f4335ad9b6bd400313e19a941e9b03a9e4597551f4335ad9b6bd400313e19a1ec5c66e9789c655ae068d35088b4073345fe0b0300e2f8770da14ae4c8a45692c8939addbeed7a91b3006e827def586f427cc4deba43db8f89cffc5d2ab9196763671c1cf0000000030db7910ec759ca0b32c3ab934092fe50b1fe9af6fbb76fd5efd7a47eab53b7600002030db7910ec759ca0b32c3ab934092fe50b1fe9af6fbb76fd5efd7a47eab53b7620a4bd1cd4f0ade45f968839d7a0f661d603f7c02d2a1c6f659e6685d67d8d7e3b00358bb3c78aa69792b91f6e14efc4dac13b46d557000000000022d1ecfafb4e1ffc000bb3b40001fc000bc79c00a52289f61d0ba312a086112ba5fee4cf65057ccfa52289f61d0ba312a086112ba5fee4cf65057ccf1ec5c66e9789c655ae068d35088b4073345fe0b0300729c8e764d6566a66b65ab3b4467b5e463984c8841d6a93a869848958a052e1acea53bec6cfb00de6f2e0b8cb0491180000000030eded4041e2c494c3e5ae391331b4ea1dc464d50a34d76178d20fe9904d041d00002030eded4041e2c494c3e5ae391331b4ea1dc464d50a34d76178d20fe9904d041d204809ea7f6bb2e840e7a71c40e435edfb9618c79f822165c721dce537b7ce52c601f44f02a47f3e123e3fdbeddf59307407d1b272870000000000a747dfd4fb07cffc000241e10001fc0002433b008d2aefc27102e8b3f7615e419a61bc394fe83ba4ac1a700d32a6ab3f00aebf68573e26613e62a825d458f5157d91f4832e66eb8630ab3dbff95551d8300d731903ca090050801af45465c96d1248532819959a5a97eacb1ce518dcd5c5a21f20676d7c893f81ba672fcfb0f8050000000030fb0b68444a03b7a3a7f079f1445cab153962fdebaf77d9752cd1c08c816c4800002030fb0b68444a03b7a3a7f079f1445cab153962fdebaf77d9752cd1c08c816c4820a2805906f085aa712b452f8f05002dd3ae71648511dc6a88fe742bdf1990edf1006b827aec87ef146557c8528760f9240e747a8b96000000000022d3f475fb4e1ffc0006567a0001fc000bd99b007ab77c02d06ed94aeb677fbafdeaf0f6c0da49c57ab77c02d06ed94aeb677fbafdeaf0f6c0da49c51ec5c66e9789c655ae068d35088b4073345fe0b0300610fa6d1e213d65b653302ee8ea682b7c454e2117939ca77ee122a5cd8a387cc199ed1bc01d18641a05aa1e7ffe74300000000031a74f4cfe217fd8504e6b210fcdf12243828a67191448b649b648f7397da08d00002031a74f4cfe217fd8504e6b210fcdf12243828a67191448b649b648f7397da08d20520e51c4633d678e5ae07dcdeb878c950195be4f521e76a8e8efb802490bc7540105dbe6edec2480181164c7d62edf45068cc3e5a800000000008b3bf941fb4e1ffc0005e2fe01fc0005ef9701fc0005efbb0005d6c86082462b374e1eedaf7f53bd44e95a1f68c522817f1747a9922db608af9f16503bff07798005dbe6edec2480181164c7d62edf45068cc3e5a83082f48df5b39fac4fe299c0741cdf675eb53aa0b936ea147d4883b650596887142e4fecf91087799de85312aa47c6d60100000000324443f3ffc7b3cc689194e0a0acbbcb943482010e6ebe895e3ccaec58525922000020324443f3ffc7b3cc689194e0a0acbbcb943482010e6ebe895e3ccaec585259222018929b9319a3c5f73c75d7696fb45a41da8842a9a1df4a94b6c7ea5ce5e4696200e405f89a110cceae2689f59d7eee20122e7b23d50000000000235a73befb4e1ffc000bb3b40001fc000bcba300c04ced284f6d465e579d8e64e9eab9c0852c0766c04ced284f6d465e579d8e64e9eab9c0852c07661ec5c66e9789c655ae068d35088b4073345fe0b03007cbeec33e4aacfe4a2b4a29b60a7b702bf3735bf48fbb86a2ca883c949c0d2c84b26cffd564411041ee5218f551ce2b0000000032f66942ac8ad4e5d6552e1c22d990c8663deedee1b0f79783ab4ab395f5652c00002032f66942ac8ad4e5d6552e1c22d990c8663deedee1b0f79783ab4ab395f5652c2034ba66b442a95a29eb695c36e912dc00d958f0a7f2ea178d8f8081115c0af1b6004ee9a0820126e33f0b27f53b37fec69d0322eb86000000000022dda8affb4e1ffc000bb3b40001fc000bcbaa009eebe57e4f2f24ec1aa880e2ea00513ab416e7339eebe57e4f2f24ec1aa880e2ea00513ab416e7331ec5c66e9789c655ae068d35088b4073345fe0b0301368e69be7748d2e13f6e6addd0a775062a856a9333dd25a1ca0662decf7bb98a2f3181fa53598fd387da63b5704250500000000339358bbca4d00397e0b4fa1fce5b7af195a8e8e14e79e75a91dc54ca34fd2c8000020339358bbca4d00397e0b4fa1fce5b7af195a8e8e14e79e75a91dc54ca34fd2c820b8ef3ff343c38e2a71c8be729700db41bfeeb0df9e57b48534227c44f6d53db600038ac68f188a776526681ef676fb5d6404d78b4d000000000022ddef7afb4e1ffc000bb3b40001fc000bcbaa0073f6d493ef502c02f82678f82b2d834cb361254d73f6d493ef502c02f82678f82b2d834cb361254d1ec5c66e9789c655ae068d35088b4073345fe0b03083415bb44cad9fc44854254a6bba65b7b34f1226bc3e844685e7e62cd6f53e7a6dc7b12d1fffbad7fe0c135101408d320000000033c82292c562fca8cd876144b725bfab4be9975cd54a5f7903663c2ee60d49fe00002033c82292c562fca8cd876144b725bfab4be9975cd54a5f7903663c2ee60d49fe20e597f8e67bfb6955354448b6d50e77ede36dadef2c313f79cd42274fa195eea001a7283956624e1d51147b90106872fe169291f4e50000000000235b9986fb4e1ffc000bb3b40001fc000bce2b00607f9501a1545d0aae13127aa475a3f25c6d8458607f9501a1545d0aae13127aa475a3f25c6d84581ec5c66e9789c655ae068d35088b4073345fe0b0308800a5f9efc7684c4fce24f11c103b04634b52d008e0272d89d9105d57e6fd8c4079e6a8331f2cc2b8f36b28c4afe3f90000000033ef407d7aa49e2e929285bdbd1dc6e4b8e2e423e0e0f2b28328ae8a8ffbeaea00002033ef407d7aa49e2e929285bdbd1dc6e4b8e2e423e0e0f2b28328ae8a8ffbeaea2084b5cee14786065b3efe381a9f7e0619548c5fe19e68d20532a00b262f8c72e3013b4bdf5074ad4c48e2669cff6b8b5bc260919178000000000088f471a6fb4e1ffc0007e4d20001fc0008df3b00f019d6736feb8fa148524c0b3fa3af0da39ae5aa4f9406e645e1d2a24f68a29124a5ed91782c9208598120ebfed5f9197261ee352b5029f9cacd5983300032db28dfb209566356ae396255132f8f8e412d6a59dd5cde82ca347f4fb2a4713d8a49dd2dd9b8019bc2dd3a62745a0000000034f19e4ac7e1b2abbded7fe0d19991cde34eb7797d8e81fe01d6e73db209718000002034f19e4ac7e1b2abbded7fe0d19991cde34eb7797d8e81fe01d6e73db209718020cafd1d29a6bfb5294fb789c8226d61a2f4b641964f2d2483fe880ebb5d6a506f0176a4e499430b47be702257744898bb3d95e06799000000000003144612fb2713fc0003ac100001fc0003b5eb001dc640b7e408921b2c99d18ec5bfee69e61d85b61dc640b7e408921b2c99d18ec5bfee69e61d85b64217790c6c0655795f7c3d47e42d94c9dae99d4b300fb7164d86058e2b22c4a6f6917714dfa4a2cb4d54bebbf3c9300ebfe1759b33d15b0b68e32999aae19bf0dd92341e400000000036c99a74a4cfec77b2a7438558a8ec53ee09c11833597c1b601c5b00c93e37d600002036c99a74a4cfec77b2a7438558a8ec53ee09c11833597c1b601c5b00c93e37d62002b0140755817c6d71787ea5004a1342bcf6f1ea8626eee46ab8affd15a5fe6901c9d30aa841c8e37e16f8095f20aaeac9869d26d9000000000023af3e6afb4e1ffc0001e72f01fc0003707201fc0004053b0052b7f1604d249547c79a4056b2969ef98e816aba7509e1003c6e1b4f64a954ba6297e4554f3e7359b508db53f0a3f072b00f579a86e813d6af2856f3308f2caf4cf1e01130aa6bcf27784bb36a2b4daea4ada3be553c9b709afcc752d0f34a0c35e3301e8f6a2fb3ca44656be20000000038f8cc9f9bbfc0ea0b35880a727940037849db6f717f146392a2bc3e971a6f6100002038f8cc9f9bbfc0ea0b35880a727940037849db6f717f146392a2bc3e971a6f6120a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e4790853e3887a8aba03562d217ed6db4fd74aefe82000000000022d21ac3fb4e1ffc000ccadd000000ea1e4a53ffa1572af733c63b530860885f9c8ad8ea1e4a53ffa1572af733c63b530860885f9c8ad864f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d730897fc76b69f1ff4b06535e7a4bc7396fb66b33194effbb72214dbefc2c7cd3220ab6cc39fe4630a513879f9f8dca27e300000000393936246926976b4135b6dca4295f45dcf95c875422b70be451f2d51293c7d4000020393936246926976b4135b6dca4295f45dcf95c875422b70be451f2d51293c7d42096e4d1ef906cdfa4084e2a8dfe662116ad8fdf25b395ec355602edc0d72eb8ea001feec80a8a9f80fbb419cd7e118c67524156f51e00000000005fb3a457fb4e1ffc000532300001fc000533f400e8ca11e6c7d6a9e15b9676b534663298040b88b7e8ca11e6c7d6a9e15b9676b534663298040b88b7c66ab236698c66f559ac918689cadae4c8aff0f630847383710ac1786f020769809abad8f93018338eb855c103f5239d75dc2767770eb45709c895c99c0c86d375ddbe478d000000003971dab9691efac06e4ce7a5483131373e84726458924fe48b7d541791693be10001203971dab9691efac06e4ce7a5483131373e84726458924fe48b7d541791693be120926c6d0e0ce17a51dadcdc5be4f4cce0175d8d7a147e294580e3080d6a22f96d00e5cae595965e89fa9f94152f57b315ca504ee1b300000000005c3fb0cafb4e1ffc0011098b000000b29a8f14049a111260586f489d72cfea1ed8ee5d492df4065de3d5d44692934635d826255f7a60f80e7e48253baecd886fd539601fd5e95efd61534d30b92d4ef819fe283a307e6bcd500d8cd35e9a7b779dbca59bd3bc77b3bb3611c370258aa6dec13d0781e0b53c911bde08000161c274080f47a95be5372ef8c69bb60ab1d4ca8201fb8f3001fb05a339741ad83dd791e1e738f19edae82d6c0322972e6a455981424da3769b3dbd4a00012039741ad83dd791e1e738f19edae82d6c0322972e6a455981424da3769b3dbd4a20593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c0826c998cd53845caec6858f3121e5d3a88df6c7a3000000000023a390e6fb4e1ffc000cf99e000000bd9857229d4c0509c753afc85d264fe2e4f344a3bd9857229d4c0509c753afc85d264fe2e4f344a3c69a0bda7daaae481be8def95e5f347a1d00a4b430b6693296894820bdc3c0ae76f357e544847f10a68f0046f53745370dbe861d57e194ddaf7ff7d5e73cc3f240515c448e0001ec7bf3b9bc72eda38c80bb7cf16e294e763e56b401fb8f3001fb05a33979cfb79c4562e819aca69ffae2ea84b9b8f29bd89bdc68be67b88c6f31bf990001203979cfb79c4562e819aca69ffae2ea84b9b8f29bd89bdc68be67b88c6f31bf992067a0592b5510496cb42f2d784cc3b933a0156b10c8b54e440673bb87c57dbb01011353eea2d4fbc06aedc288e493b70de32b3e977f0000000000adc777f2fb4e1ffc000d5e0f0001fc000d5e4b00d8155dce6238737a6af04e068bd92048e68a7f51212e07f7407be541b585ff0a8225fa1afbcc9ac8dc82946c9cee9ab3e8fef5a5d641a57bdf1523c030a73d8c1e640d29e2257042a39bbbac8d867f69ae252e146884816b98ab0d0526ed4992d9cff22ef04878423f66583382000171b5c04007f6af71d99893478feb52df0f5a770101fb592501fb592639a1339d9bf26de701345beecc5de75a690bc9533741a3dbe90f2fd88b8ed46100002039a1339d9bf26de701345beecc5de75a690bc9533741a3dbe90f2fd88b8ed461209b9054ff7839b940277b8eb8211570b2f16850ef729ee635e24d722fbc4a462301852d4f5bcc34685e3583dbbdc92e9bedd3e985a60000000000c6c74af1fb4e1ffbfb1e01fc000107bb01fc000134f400891cbc8a94fa7fea64ca9994870dca0f75bbd075359c348a574176c210c37a25d4ffd917866fb0a3e54445646929fac8b7d6c71715913af443249784300efda51589f86e30cc2305e7388c01ce0309c19a182cf37bced97c7da72236f660c0a395e765e6e06962ecff5a69d7de0000000039b88e537c795f0b093c951539695fd4819a91a542b247ebd3a0ddd6a4c1c43900012039b88e537c795f0b093c951539695fd4819a91a542b247ebd3a0ddd6a4c1c43920bb600d779c7be93a83b9d7878fb38b0b1b7ff1390b231c5da8136b674cde822f01fd9cd0a5165717d4b3a17afddc669f3fd14efbb5000000000082a2e172fb4e1ffc000ddfee0001fc000e0d6b00f5cd552d14676526ef325757eddcfa285b15ac34bf951db34349385992e0303f21fd7240e44e4b0222319c7fcaf88f86259ffd3fa8430e4665f2e1f53090d98ff5c2f2970197ce80ca8cba9431f7dd7cff5d9fc9c4e99c2ed06e598f273d31dad8d8d05655c8b04599495cee2300018e976c7a2f79745d70e41aab1e61cb5f4db4323c01fb682001fb01bb39ec834a6c7ac5ebf5fd885a271e2149099e87e89a9ea30f573b4b699b9399c600002039ec834a6c7ac5ebf5fd885a271e2149099e87e89a9ea30f573b4b699b9399c6203eee0b9d7239564719e9ece229505909d518b38defcf16aa286871b5d6afae03007e345d48c4d9a24dfed5f23ce04963868ae7bc3e000000000086d10280fb4e1ffbc4260001fc0001962b008b7355042f324a44995bb21f9b68d63e4ae3ca6b959ccc5ac3cb8830eec83a7f15d433ac5452d425b2334b22379811352d9988876a6e586d975e7329300617fffba2681e4712782d97b84cb41b722d56089c3f3b3978b8724cb02baf0f67a57e8d1e2f8227d21700f7b10230c4000000003a3e75555ef79cb77c55684587b65a9ef728efcbb443b46fe2e7ed3e660c4a660000203a3e75555ef79cb77c55684587b65a9ef728efcbb443b46fe2e7ed3e660c4a66202cbbc61af11fd5c13e19c53fe37aafb9ec1793a6682273ac1c639ebdb605d36101f8bf45c29243a614283bcb7e6ba1995124d670ce000000000067507615fb4e1ffc0007ca830001fc0007cac3006dfb5ed0a495b0082f54056634d8bc1431d4f00f0aeea2780fdcce25eb1ff50c0edafd09e0397ec1201d032a4c937947e7d6469d39b2092dfcaa0b723087a55d353f1c76f34d45486140b3242762e03d9f688b7be28be4389f552b7a057e3a014f7f654cf7da7260b5ec1c15e5000000003a541549d161a0e134f54db0afaee615530bb6d84e353b82afc9af76a9a393290000203a541549d161a0e134f54db0afaee615530bb6d84e353b82afc9af76a9a3932920fd9f12dc7a00babfb75867303b9e99bed0d2ad149074350c4659612c0b88cb5b00d488c9d5bc5de3c5b9190fec92c5b37e705ce3f700000000008b3b2314fb4e1ffbc8a50001fc0001197c00abbbe06cd2bdb3615599a7576dacf0cc3cad128728c20f725ddcc44c5d6c728b05b886805ca125afd488c9d5bc5de3c5b9190fec92c5b37e705ce3f7300a97f109f81f15cc0b6af0a57ec93cf9f201789fd28494baf1840594d4bb233cb790f4ba434c49ecb6a1ebba61beec03000000003a80d01eee0c4b79f9de8393f0260fe859677b6bda207a21fc3217a9ae4b5a030000203a80d01eee0c4b79f9de8393f0260fe859677b6bda207a21fc3217a9ae4b5a0320035a4baea91732fc217a20da6b7b6759e80f26f09383def9794b0cee1ed0803a00cb3b7402b0dcee772112cfae17e12cda1eae0dd600000000010000000000000000000000000000000000fc000194d001fc000194d201fc0001a33d00e3f6150f12df79d8bf1fa5513edcc000b93d388ae3f6150f12df79d8bf1fa5513edcc000b93d388a2c0be6e924cf853fa531434308f0c389449ec73930000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003aa33cbad1659ba0bdf6530b5ba543592e2f30c5a35cd89fac77604317cff0f10000203aa33cbad1659ba0bdf6530b5ba543592e2f30c5a35cd89fac77604317cff0f1201927dfd5c8e7396db11536e478f4ccba1a05c7cbde3fcd5c2c98eee94178916d01cfc20de0654c5bb2318915c8f9a3bc3395f84e64000000000074cbc88bfb4e1ffc00035a160001fc00052a63002576863b75bc6a1861ac0a2f0e18ab0d373986b5e5abcfb8f638610b4b5ea0b23d82db8e7560b4003b9fac2da702d7161a178f359f98f0276d9556b1308130957c5939cc5aa59a9d7ebb88a03c8e60175230f87927f9485d452f6c844454148d8efdeb9e3216600b7f6645ecb8000000003ada735b7fb780232ed20e0a96d293385a0793ab7c5c360dd356c98192cc290a0000203ada735b7fb780232ed20e0a96d293385a0793ab7c5c360dd356c98192cc290a20a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e3154cf88c4f4815dbbf2a3912e55b1bd7d84fd8a800000000000235b9d1efb4e1ffc000ccadd0000004c58fc64d6bf36b4cd655f04a3e35ddb1ed7a48b4c58fc64d6bf36b4cd655f04a3e35ddb1ed7a48b64f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d7308c290b31d2e878c2d7235efb0c61f423aa37742a31318e61f8bb0bd6c110a892dc244512fec12a8b0fe7cbb08e12be28000000003b056202a743c16d86aff2f8ef6cf5d402e312f70740b9ae20ae92e47f1de1740000203b056202a743c16d86aff2f8ef6cf5d402e312f70740b9ae20ae92e47f1de17420a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e2945dcbb68ad19e70cbbd741c61b2267e08ba65182000000000022de150efb4e1ffc000ccadd00000042d81ce6e9a394d9a408d1fa828a8bb7bf84d17342d81ce6e9a394d9a408d1fa828a8bb7bf84d17364f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d7300d9ee7b7e66124c4b047e1f93aed5a764ed7384292737ea17f3a7e429ce3f24d602d54b97f72d181b6f093da9b3ad3f5000000003bed128ba5c04b627627cf5d9f1dec0622caef4725d8d9d4c37c65642dce92ff0000203bed128ba5c04b627627cf5d9f1dec0622caef4725d8d9d4c37c65642dce92ff20ff92ce2d64657cc3d4d9d82547efca2206ec1d9f5dcf2776624bc0a58b12ed3b01cf2d268921dbfa2c604c708275f79623d67b0e6c0000000000ae22e973fb4e1ffc000cf13801fc000cf17501fc000cf6e3009c543dbc00467b9451f2e47e7c6f01f7695c0451ce7f101b7f075273c892063b1b8571311737a5767f95c0f808aff27883260bfaf9cfe2b84519a6b2308c9c5c77fe321ff0a115d1ba5bf7462063ef21a82ba796415f4ee538bf9e8a6a49707530c72cbb6b60026c46ff1b9443000000003c7e5634f8fd8af476905ba2e94db5d6b46c41b22445382bf949a71cd16fc18f0000203c7e5634f8fd8af476905ba2e94db5d6b46c41b22445382bf949a71cd16fc18f20a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e15241e1813fbd233ceb15a094365a689154d9b9a0d000000000022ddfcb3fb4e1ffc000ccadd000000055d0c3a48dbbfab9fe7e77aaff5818e4d5a0ef2055d0c3a48dbbfab9fe7e77aaff5818e4d5a0ef264f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d7301130b42d6eb505e811dfb18ff87c4bcacde56b76a7d47a8db88ca26e75f5c2eebdd767d440f375784f9d1f127f57c977000000003c99840d0c2ebb37b76a6a9dce2b876822ef969f7c2dabe67f0e7f071f2b03180000203c99840d0c2ebb37b76a6a9dce2b876822ef969f7c2dabe67f0e7f071f2b031820a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e448fa93403837002c7b2d0de6c44892051489928ac000000000022dd6633fb4e1ffc000ccadd000000c682e285e7a7bd65e9268c1bc695091eb4ce5a8cc682e285e7a7bd65e9268c1bc695091eb4ce5a8c64f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d730121adeaff038746afb470b84fb3a58f1a3bf304cac771d16980845c4902e5da34d366394c8e84a46d8bc0c0a1da23cc6000000003dbb7de94e219e8f7eaea4f3c01cf97d77372e10152734c1959f17302369aa490000203dbb7de94e219e8f7eaea4f3c01cf97d77372e10152734c1959f17302369aa4920b23e38fe428255d0068cc218c2c831e3bfc87c8249f3cba941e126053fd73b8a017aebdd020a3c7d9accde7db5d32c6a06d4c8ee9f000000000034244094fb4e1ffbfb9d01fbfe0d01fc0001195600ecb1486be55e4301c45b87cbad94daa8c5d17fdd6cc4a7bb877a80c11ae06b988d98305773f93b9856bcf3cac49235537d6ce0fb3214d8850a6db77730139b654f0b1c031e1cf2b934c2d895178875cfe7c6a4f6758f02bc66eea7fc292d0040701acbe31f5e14a911cb061a2f000000003ecdbedf3d9a13822f437a1f0c5ea44f290ab90f7c3bb42c1b5fd785b5f9596a0000203ecdbedf3d9a13822f437a1f0c5ea44f290ab90f7c3bb42c1b5fd785b5f9596a2072f157ae4a1ecfc6aceedf008abd5679ec9731abfa05dca49eba50b1c0b6ba860021a6e0e4828963d5f39e3129bbd9e1af873671e700000000006c3dc02ffb4e1ffb1c6501fc0001f46401fc000532f5001bba3b56ededb76c1834f3b3e02c159aba4777a61bba3b56ededb76c1834f3b3e02c159aba4777a6415e1236ed7df54649a880d353acb6f9ccdc622c300634f8b926631cb2b14c81720c6130b3f6f5429da1c9dc9c33918b2474b7ffff239caa9b59c7b1a782565052232d052a000000003f43ff3539e5a4fbcc88c7f031a544fe7e62557b5963cb7e43157ef73abfb13d0001203f43ff3539e5a4fbcc88c7f031a544fe7e62557b5963cb7e43157ef73abfb13d20476ad8662b3be5582b98569b76f66d2eecb59a943e9fb28bcbd23a10d53817bb01127e174ed242c758d4db9b7d5b19c1e0743728960000000000b29d5bbcfb4e1ffc000de50401fc000def0c01fc000e366a008ee38b4c9c407b21612862db1ac4e98a6edacb4b62026629f37f587b1dc70ccbc6732225803db4e3ecc3795b4c3e8c5b840dbfa092df1395237f2f8a30980213c5fa8031aff096b8a3eddeefd0584a0e5c2492f631ef67941e082763250e2615975db1f1bfae631f80d41d839a000100120432e9d299caad204ff1ec0c515babddc28601fb8f3001fb05a33f669abeefbe8527a5ca342037f8f97f5e6c8a65f559936abe546601efdab6030000203f669abeefbe8527a5ca342037f8f97f5e6c8a65f559936abe546601efdab60320106da0d689007410d07536c59586b62f5507aec775cc2a9cb4b73de8b7681cca0091c213cd9929a245bcfc03a9add339a210101ea3000000000022d17c70fb4e1ffc0006567a01fc0006c05c01fc000bdc0b0012e05b745751ccacdbc852c12ab9c3b9feb5b77412e05b745751ccacdbc852c12ab9c3b9feb5b7741ec5c66e9789c655ae068d35088b4073345fe0b0308c6eabbfad80e5acfbaa7a4fc148317f52d80d4249b62b9c3b23ae8592cb7306e798cda7c90dd366ced083618fe2bb8c000000003f960fd8d414906a260cd07db16f743f65306823355b61b5d3ad4bdcf91845490000203f960fd8d414906a260cd07db16f743f65306823355b61b5d3ad4bdcf9184549209c8946bb69fa334913c78c08bcc2ce898861e57a316b6edf4b3f4d6d8de49d33013f7a3f24310795b901908ce57d40dae9d09dc59100000000010000000000000000000000000000000000fc000196f301fc000196f401fc00022899007118238bc3182204c634d9035a968e9b59cd11971db884e38658de13612ec46d636c67f26d3c43ab771e413eefaafeea2aa4c0ecf2fad265164e83f330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fe25a5d51edc1942b3e68170fd693bf8068968ca6e1be3a1721bfe5ac8416420000203fe25a5d51edc1942b3e68170fd693bf8068968ca6e1be3a1721bfe5ac84164220cedb19ac5ae1a42eff8e7bc39aa68803f6828db1549bf1f17f041816c961f8cf0163df30d171377fbf7611b741436a40d70969a98a000000000086d15a70fb4e1ffc0001aa9401fc0005f08501fc0005f34b00d71dc86bda7e222f78c9e45f22deae9437028650d71dc86bda7e222f78c9e45f22deae94370286501bc18ed01b8e3a9f78a209e7eb7f07edcdacb0ff3091386d3acee0bf9044cce40a07515289589b68fc9b8c8e5d184471ed7982106b1e11587af4c9e983883baec00b67e473000000004008a18371798ba28da7c9a581daf0aa92c4ac0b980c3438936823274f64dfef0000204008a18371798ba28da7c9a581daf0aa92c4ac0b980c3438936823274f64dfef20efdf644f2723689338340c980bacc492aaf0da81a5c9a78da28b797183a10840019bec606b655f5b5bbd68207755e614a79dbf4db30000000000a5e30a44fb4e1ffc000123a90001fc000123e300207d0b14af27f5a735cc27f37c29428f99fdc25c463b7729308cbc30c9c199ccee5a77921bb0ace59bec606b655f5b5bbd68207755e614a79dbf4db330121af4d4c49a65e1439a27ce0f39a2eca5ff751e9998c0fea7a3c2b13731cfa47fc6a56a313a38b448f3792fb60dc11700000000400c7f8990e6f8a3993b7d5900ea0b58e18bf86ba9b147bdefcd0df4cda1887b000020400c7f8990e6f8a3993b7d5900ea0b58e18bf86ba9b147bdefcd0df4cda1887b2017808983e70240144c4c811a1c3404d9d2f1395dc937dd761dc437d80e07928401d45a97fcf480feb7b262a80eda5b78a2a1a0621600000000005911296afb4e1ffb392101fc000124ed01fc00013d4b00724befff5e89d92cbad3cb0cc8281020b0243bd8724befff5e89d92cbad3cb0cc8281020b0243bd8d45a97fcf480feb7b262a80eda5b78a2a1a0621630848bfbe1bf50debe1322e14c9115adb3b96e5b8a3ae96beb7e2161281d9e56c30e43478d6f39835e3533a1c54377258b0000000040784f3f9a761c60156f9244a902c0626f8bc8fe003786c70f1fc6be41da467d00012040784f3f9a761c60156f9244a902c0626f8bc8fe003786c70f1fc6be41da467d20593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c02024eb44eadf4a67de93988f1400bfd5fd6fdbf830000000000340ae50bfb4e1ffc000cf99e000000f37ebd7e83f4185ccc5fb617a7ac9e09c11ffc12f37ebd7e83f4185ccc5fb617a7ac9e09c11ffc12c69a0bda7daaae481be8def95e5f347a1d00a4b43082f60dad4b7b498379d1c700da56d4927727eab4387a793b861a96df47bdabe5666c270acf04b5b842ab54045bbf102a00013e8b10646ee9d6c28d75c280b357dd3a9ae9f96201fb8f3001fb05a34106bef7acd1243652495260325ec3baf5bba47bb6e5d934c67b96bb24e3af1c0000204106bef7acd1243652495260325ec3baf5bba47bb6e5d934c67b96bb24e3af1c206658709bcdba4349bbf6d9fad0c66006993521ad1b989113855bf751a5ca1ff301f153617d41645e0e25985e35c09f98960f1863dc0000000000c3c91328fb4e1ffc00044ff60001fc0004c9730032b8da1c9e22be858fa29f61e92d6d48eb84e27032b8da1c9e22be858fa29f61e92d6d48eb84e270f153617d41645e0e25985e35c09f98960f1863dc3098e7dca1b8dbcfdc54faff65b94f81f2e3fce6440bb10848d434a96ebe30ccbb33aa586a2d0ddce112e38cb09bbf13c70000000041c4a6b724a0d25cb089ef946b7c1985a2815bc6a4e45f15bbcbd445b6d10b7900002041c4a6b724a0d25cb089ef946b7c1985a2815bc6a4e45f15bbcbd445b6d10b7920a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e172c58166b1f9c8d9f67b86e3812f98d4bfd86404b000000000022dcbbe9fb4e1ffc000ccadd0000008164fcd1a488ebde9344cbd205ce705bbe3121808164fcd1a488ebde9344cbd205ce705bbe31218064f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d73007df25a28955c903cc19f836a4daa0842d203cfc0dc5ae9b57b8246a4787ee4c98ea3f2586203315d61f4e77b6c80dc50000000041e41c6b6e1b1c43e73c7644ea36eb622bee149ab05693ea487e784614e524fc00002041e41c6b6e1b1c43e73c7644ea36eb622bee149ab05693ea487e784614e524fc207a644e33e16840030e5170f7e07877c4f992de0d330c7ba1568a651edc3c4cbe012c72148f57b165ac7a3a23d0a28ee3baa6675b8f000000000095f8331efb4e1ffc00021d3d0001fc00021deb00df7e1106ceb6cbdd287af2c99fad3d0d9181ff127efda5f8279fc8c7490aa37ed57903870a1f4ee1fd5780dec499c5f53a4222c6e0a5e3bd74097a043099567cfb20c6bed5d20638c31e7e512aedda02649e82f2b955ecd3e34f73c2229b350069f6e74a4304acedddd87997fe0000000041fb85bb67981f4e1fe41e0f7d520bf6df2167c9ced5e51fae33343f98d9cc9900002041fb85bb67981f4e1fe41e0f7d520bf6df2167c9ced5e51fae33343f98d9cc9920cc86f090d7505156acdb61b8b997eac5cbc5c77e72fd3c04ccc0a01a77183f210104b4bd6b5d6e830b55249ec9858328a1a1f504090000000000019f8febfb4e1ffc0002f8cd0001fc0002fa840040374e1c147337992d41ef2dfc974f928bd2d5a607ee5dd8d1e99e4bc8e015d94346580d7cfb1c44aeba71ea426d63532121268dec246f833444bb33308e53b8ab39fcc259aa22b93d1ab4e333353e6d56b9bd4d194985a59e0de5060c1225588a256569848ea421725223711b00000000422456a81d1601f5aab4494d935919058905ffe2dff342e8be1345f5e5b46c51000020422456a81d1601f5aab4494d935919058905ffe2dff342e8be1345f5e5b46c5120f9cdc515389213075782c4f03fad8a5010b7aa4165b804fbb1caae54c1c0f15701e1e77f1b5b7d2696a2836aee5e97b0eaaafe9fd000000000009b8aefd9fb4e1ffc000533b001fc00053d0d01fc00053fdc003d88e6f4cd4c285f48dadba815f581acc2e2df7c3d88e6f4cd4c285f48dadba815f581acc2e2df7cda952b3b45775c0af85fbe2e2ab21549d86beb0a3014f9192c3986e589f919f428c43770c3eca5c4ff3722d967d8f0d4b69ec3ec02fd876737fb06880a54566f5639389972000000004289460073f565eebd310b303cbc14fcee17c4df56a3b09e42888ded565599640000204289460073f565eebd310b303cbc14fcee17c4df56a3b09e42888ded5655996420d0407f4f9a7f087c1dd689e30783aa29dc3ed7da4b1b571dd314adac9baaa61e003b79244bcba351a570b19909002352062aa889ab0000000000235a990afb4e1ffc000bb3b40001fc000bce2b00f039342be55b7297da4170afd2df995d185f699bf039342be55b7297da4170afd2df995d185f699b1ec5c66e9789c655ae068d35088b4073345fe0b0309349d9598c25eb5aa9bc9d29c5c82fdbeefc73d1902ab2eee457b9898933a782f7db5676929c1cf3041db9322c06cbdd000000004292028ae9eb69f51d35a8a0f1cdd625f6dfee2a9ebc7bd4d9b7cb99ecc43f9b0000204292028ae9eb69f51d35a8a0f1cdd625f6dfee2a9ebc7bd4d9b7cb99ecc43f9b20a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e6ef29d62543892b99ae4398060c478dccfc4ce432f0000000000235afc03fb4e1ffc000ccadd000000ecd8bcbf77d0dae7f59c750bf68d5d33a45ddfa2ecd8bcbf77d0dae7f59c750bf68d5d33a45ddfa264f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d7308f70ff352844250e267b31c0ddb83dffd4cac43532194bd47cbabf410ca29fa7f1ecec08c8fde8c0d13910e903016d5a00000000429e8599b012fb642220d2308c8747d148f14fd3d92e169e5a5bce329853ef40000020429e8599b012fb642220d2308c8747d148f14fd3d92e169e5a5bce329853ef402003bdcb9deb0c0f2f807aabe0edf471a0bdaa803cf56fe0e855c2e60c119ee86a011574764041f46b7e8b0a3e77991a49c39f2f47f900000000003419c8a3fb4e1ffc000bb3b40001fc000bd23300f9c8a5855606a8895a4e3efaa42d987b2b7aeb0ff9c8a5855606a8895a4e3efaa42d987b2b7aeb0f1ec5c66e9789c655ae068d35088b4073345fe0b030814562b9c96db22a34d86e5c8db1fa30cf322fc3ccf743d5253f37e1cf09fb6347cc57bdbf221f076bf7c818caeffc430000000042a6958a544309799f965d193372baad8f38120a117e3700ad2d62ded1ed440800002042a6958a544309799f965d193372baad8f38120a117e3700ad2d62ded1ed440820c3448a2225a03a273f6a972bedb320c0eda40dfc46a11cdca62edb64212e1f3e005f813b236a6fbe45983588d7851c9344abe32d9a000000000023a67a3dfb4e1ffc000bb3b40001fc000bcba3009b6fde4a7f45246abc4d043aeab7c7d35934580e9b6fde4a7f45246abc4d043aeab7c7d35934580e1ec5c66e9789c655ae068d35088b4073345fe0b03091b5adb32d0031219fb93e5e8b20219b07b8a7860770e7d8935fcaa32ec36d75458180b71fcbd20a808373a16dfe972b0000000042f67134f85223da03fd3a670e68802d959ec1236fc6317b855d7133df4ee59400002042f67134f85223da03fd3a670e68802d959ec1236fc6317b855d7133df4ee59420a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e3054331ff5356c8a834bc40ec241aacfae8bf5c54e00000000003424147bfb4e1ffc000ccadd000000bb34d97e1f0a6406ea00f10eaced5e3ef227a5cabb34d97e1f0a6406ea00f10eaced5e3ef227a5ca64f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d7300bde30ce81e7c6396e334eb1bd788b683535eefe9911286bb42662c46e3712ddb5c7c24d7998118ae089e804e14efee500000000431514b6af73d8a20f06ce90b838acc055d749d77762adfb29a918dbe7611352000020431514b6af73d8a20f06ce90b838acc055d749d77762adfb29a918dbe761135220319b982bf533a97290333d1a2dbdc0e5d516bd1c2add8c0eaa6d248fd26d732d007a4bcc5bcf61fabd62a57eae55f427a8a1fb8800000000000022d8f465fb4e1ffc000bb3b40001fc000bc7cb00e921c4edd1f6b892477f9b5eb39a324aa6e5839ee921c4edd1f6b892477f9b5eb39a324aa6e5839e1ec5c66e9789c655ae068d35088b4073345fe0b030981f8a7f20ae3ff84c15f27a7157dc2e4935e956ed25166035e012ecd7f0885d961564111704303642151aa6fbdf34f000000000436f16038374090405c95464197b0a756aa8ec72137ddbd21161fcc6fc3c61f5000020436f16038374090405c95464197b0a756aa8ec72137ddbd21161fcc6fc3c61f52025ca852a8da0b2ff4aac4af3ae4088c7ae49c0656371511c187f4de7f1f3b524018bbebe630cc30eee2942c1f398fdcd8ec7ccc8cd000000000003d8c6fbfb4e1ffc000b21600001fc000b42ab006eb2e3cb6be0a0244121fcd374a5dd38e4e0ec33e7cbf5568870f2e301ec84dd720ce2d71d2ef6db3a840c9fab8a7618147fb2f3060fd847cf86f08f3007bab9e0cfd301779007735cfcd14445ef09191df5a8ac39aa177abcd56d20e46f7aff4286ca6ff02f4747c0534dae9a000000004393fb7ebb6fa9df7073cfa5bdd241f420520e1a50e6f3b6f9c436d578bb26e20000204393fb7ebb6fa9df7073cfa5bdd241f420520e1a50e6f3b6f9c436d578bb26e220910cf7ec24b21aa8582d11d9a17fc912cb0f9688e4426100fb96a7e08d3a712c0017c0398111d8169fa33a3eebfaeb34ac7b82109c0000000000235b320cfb4e1ffc000bb3b40001fc000bc783002fa548f62b9105adc27c7c69f93e32b395009dfd2fa548f62b9105adc27c7c69f93e32b395009dfd1ec5c66e9789c655ae068d35088b4073345fe0b03006e17d8852c49d0bf9ca9cb2aa16aadc523dcba6af2db6d774b3092f8522595b72564f777a8d60ad8ea79fa1c817068c0000000043e49c1f2735906dc298e133e1d22e8fe4a2a4b23e05e871deb6e99dd6a924cd00002043e49c1f2735906dc298e133e1d22e8fe4a2a4b23e05e871deb6e99dd6a924cd20e0afab253c2a299493acab401cb0ff85bde56b38d310e86627713c849fea165f0066ca67531d6cf56218281080a0a9903032bb0edb00000000003429c6f2fb4e1ffc0006567a0001fc000bd99b00bcb01d935cf0b393aea40d7f0b39f24f27f364f5bcb01d935cf0b393aea40d7f0b39f24f27f364f51ec5c66e9789c655ae068d35088b4073345fe0b0300c33a73d7e9ef598da0b1b9ad04b12f98da67f75d66f1237866fa64f4586a4b156a83e8c79b38139d32f452dee313bf600000000444d4d1e9850cf19adcf3aa6e01e8a198779eecc8d55fe8bc9715726efc58987000020444d4d1e9850cf19adcf3aa6e01e8a198779eecc8d55fe8bc9715726efc58987203cbfe25dc4f982ee3ce537123108745285809ce3d8e5f71c6049b1b328356808015ee12a27a3bdbea28f50b697200e612dbd4a249d0000000000cf9af29dfb4e1ffc0001167d01fc00011b9701fc00011d0b003cc1fe7d3423d6a9a847723ecdee0368320171ad3cc1fe7d3423d6a9a847723ecdee0368320171ad5ee12a27a3bdbea28f50b697200e612dbd4a249d30958adbe9f954ec23983c4be5788e86e0df30fed1d6852136376b49c1a24e0fe1da1178b23dec4ea098b9e355aba8de0b00000000445e313b262961a5244f30e02946445dfcb52420767688db8aaa6cb5f382052c000020445e313b262961a5244f30e02946445dfcb52420767688db8aaa6cb5f382052c20a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e4184248712d2e21cddf89379ad490e99dafabeccc20000000000235971c3fb4e1ffc000ccadd0000000a2d318258cf9455a414d2fbe30c69f5ce8d09290a2d318258cf9455a414d2fbe30c69f5ce8d092964f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d73012fa57a5676925e8dfe3b340df2132f5844ad9f89594b04efa28fb4fb884fe21f411fa49120ed7a60ce9381a54232a1000000000446395517d8dc7a2fe06ffc2dcb5300c248a324b9bd5bd91532acd77eabb5d69000020446395517d8dc7a2fe06ffc2dcb5300c248a324b9bd5bd91532acd77eabb5d6920e51b139b1838d2b9b4bc77080544cd03c11eeb0c5b70f5af44f33fc940de433901a38211dfb24c64aedfd08760984fee730d6e60cf00000000010000000000000000000000000000000000fc0002ddd70001fc00033e4c016af70254b26589b80f06011b3de26f7fbf715b8e6af70254b26589b80f06011b3de26f7fbf715b8ea38211dfb24c64aedfd08760984fee730d6e60cf3000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000447962fd8a1e759aea5e00d0272df10c38deab7fd410c916a2b77eee7276b047000020447962fd8a1e759aea5e00d0272df10c38deab7fd410c916a2b77eee7276b047207ebcb8e4c5a9e6837e65e818f89ccd6063c1c5c3604b073ab60015b7ea7f41fe002c491d6e81334e057e3a1fbf1bb18ef2b90fa19d000000000022ddbfaafb4e1ffc000bb3b40001fc000bcba30075c6a48d5a612acd4bd3feebe0f6da422f685de775c6a48d5a612acd4bd3feebe0f6da422f685de71ec5c66e9789c655ae068d35088b4073345fe0b0308d3a62107f6534da1933eae8fae34d5b2c7fce2a39672e9c4473323f90dd9cfb333cc4d39b45cb220460b63c1d11009b0000000045a9800145a0abd2b8f4fe1fed333f712091bc46b4c1a4ed4c21390ec2ddeab600002045a9800145a0abd2b8f4fe1fed333f712091bc46b4c1a4ed4c21390ec2ddeab620410c3c13c2080484354a44116a425a0582bca2873f9ad8e9e914eaa9962baf6e006fa76977109534ddafa6eef7bb017d4c3a882222000000000036da6255fb4e1ffc000bb3b40001fc000bcba300ddf3baa5c5a1d3992213b6780d5bb228d54c2928ddf3baa5c5a1d3992213b6780d5bb228d54c29281ec5c66e9789c655ae068d35088b4073345fe0b030808963d5165e95a9c68094c7ddf16300ce59f127e4555633603efa4e776b026819e534ec54357e25ab467c9859e2a14d000000004636ed7acbacbc76aba60aa7a1011688fe9ad5fd701d0bf8fc42a502ea3e65430000204636ed7acbacbc76aba60aa7a1011688fe9ad5fd701d0bf8fc42a502ea3e654320cebdbed894cf5595b08368bcaafa6112fa743ac8bf50ec4788f5ae60e7783ac0007733a403791a61f42a529fd3281758a248195249000000000086d10594fb4e1ffbc4110001fc00019493006a6434babd99215b4f98316b3f701ecb7cca0aa2a820f49ed49d977621b499c9fc344f28a9b1c0cbb2334b22379811352d9988876a6e586d975e73293083a6548569b0c410d7e1dec3f4f5a18a0790723a991d3b9477a9e062c660959bdbe5b3c1d231195801b9072ae94279660000000046ce2b4b45b41f52b9e634ebc3e8b37c3e1685dcf53092521050884a2dff406d00002046ce2b4b45b41f52b9e634ebc3e8b37c3e1685dcf53092521050884a2dff406d2013f4687763666394944279985ab891c698a9bffc567be7751a80488f98f0cd210189e26bbc182969b51b8d729c0196c0f7b29811d4000000000036caf173fb4e1ffc000bb3b40001fc000bd21b00f07a6a479a2cd5a6e130d51d128a8ca998d1b209f07a6a479a2cd5a6e130d51d128a8ca998d1b2091ec5c66e9789c655ae068d35088b4073345fe0b030870b84b1994be69b0dcfee35aa1e5d1042ab1407b1eb5622eef0fa248e562220695ca423ef6a41abdeff3d802d1ca2440000000046dbd118b9d9b138a5be20446ae3448e8c41acc8c28411848fc85f563090b19600002046dbd118b9d9b138a5be20446ae3448e8c41acc8c28411848fc85f563090b1962094aa08aaeaa7f1581edad08db7bccb4cb24055fe20dd3c783df878e8f12a0042001bc18ed01b8e3a9f78a209e7eb7f07edcdacb0ff0000000000a516e93bfb4e1ffc0002925d01fc0002aaf501fc00052cd300ad0d1c7493405ae2836390ada4ad0227c8278f39e3bbcadcc1f89ed98a2ada3473bde7dc618cf3a763df30d171377fbf7611b741436a40d70969a98a3097adf3867ae5155b18345e44e277ab26b9a497c7d0cf9b53bdc42362dff3642c922d1d10e277ce6bd407f48bfabac68b00000000484c56b2f30e7a223d5a633d19bb54100bf9bc8a1a6ed1e72ba86c9758558d19000020484c56b2f30e7a223d5a633d19bb54100bf9bc8a1a6ed1e72ba86c9758558d19205b016215386c035a42042a93736befccdb87c30cb90adc3b1279da58ac57cc1401112c35b14433e8a28f70889c6d8ca99095bf0a91000000000036b99e7cfb4e1ffc000cf8b101fc000cf93601fc000d049300f6dfd96165379ea02d0e5650085cbc5765d22df2f6dfd96165379ea02d0e5650085cbc5765d22df2c69a0bda7daaae481be8def95e5f347a1d00a4b43093b18f6658a9d0830057a2a0513c2f4bc70eb0c41df4346fc849170fe0b1374716d0d1ea24726fdce68636fe713ef44a00000000485d33cc5a823b6ed0ac345b93438ecbfc44aea7964ca95cfd998dbfaa16ec76000020485d33cc5a823b6ed0ac345b93438ecbfc44aea7964ca95cfd998dbfaa16ec7620a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e4c9d7137cc2ba84ef788209f51340daf53f40a2437000000000023594254fb4e1ffc000ccadd000000192cc27d195d1a06bd813765887587824d036b25192cc27d195d1a06bd813765887587824d036b2564f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d73015f9da603c572257802a689964ca8f4d96f9b94f33ab75968c9cb6c730a28d50b7bb72ac2cfceee6ab0755ead9cb53cd0000000048c29275ad2ba66954b3ed4d58a29c799da0abcfbbd38da9646079e94610c8cc00002048c29275ad2ba66954b3ed4d58a29c799da0abcfbbd38da9646079e94610c8cc20d3ca56e9eb70d7e9a43a93f27446d29c9017bd3225905e50b1d56daaa6c515c10089ffce4da0663d5e5ae1a930ca9f919b8e7500da000000000088f459e2fb4e1ffc0005e0ee0001fc0005e26b004188469fff56b20349d06ab783d8e44b7e698a734188469fff56b20349d06ab783d8e44b7e698a73776e544e9097c2457f74dd5bf1ee545643d2ceb23090dfa669abbc6504966bf8cc2b4971db18a5052b70475fdd5e6f427349635ccd6b9c7869b52ff3133c5661412ea5ec130000000048eb1b545d87e712edb1382d8bee300aa0bae80bfd0c347920f4afcd0ea34b0b00002048eb1b545d87e712edb1382d8bee300aa0bae80bfd0c347920f4afcd0ea34b0b2093e40ad62d5fad58ff996065d66ba1adde1f4c1d47ab9407614c98f8523d95ff00c8b1d47b6f0a98d16aadcfa32910b454024fb63a000000000023a84ebffb4e1ffc0002199b01fc0005007901fc000607bc0098bbc48b046bf66975aaec4bc7a1d9224d75c75e27ab63981bb3d5f5b0375ebd3c709b95174ec67a253cae727106faa4bf76b0b4f8375091889f671530051b1a638ba22cba300ba0836304586ba5572a525622c4dd49e7178214985277eebad66a371253163e35e93d3b44081b00000000493422474d55896888a6eb24804cf3af1d7479956d6706a44ed80aa5cde12af7000020493422474d55896888a6eb24804cf3af1d7479956d6706a44ed80aa5cde12af72054d645b1fba1e7adff0e213c3fb1de352e6f806fc7c5f9d0b716599b66c7261a01c940f123afaf075e70ab25bc4cbf59248e37e7e400000000002358395afb4e1ffc000bb3b40001fc000bd20300d40244c9f7115897ec1afb80fca9e5c7cbffa2e2d40244c9f7115897ec1afb80fca9e5c7cbffa2e21ec5c66e9789c655ae068d35088b4073345fe0b03007e428808a71ba6201f8bb0a3dd71be6de31816eeafb1108b3710e956db7ef5bcf2fb8bc9976a20799077a24fa847d660000000049f9818da1c1948ffbd964d593b7ef590031b794617e62587d984f61f2fbe20e00002049f9818da1c1948ffbd964d593b7ef590031b794617e62587d984f61f2fbe20e20a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e2339ebe0fa295b303b5b8aadfd91a64d75e46740590000000000235bef4bfb4e1ffc000ccadd000000ec97fc04493eb004db432813f88f3ce6e730baf5ec97fc04493eb004db432813f88f3ce6e730baf564f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d7308c1cc0f5e0a5aea680a170ec945074f5b83d83db4d208854204f57c0de220ceb63b0121bd2a7bdb214228338c575ff6f000000004a7d3e011dcbe58192a8bee91d366c6f3720d8247a7dd586b8a50a0159eec9370000204a7d3e011dcbe58192a8bee91d366c6f3720d8247a7dd586b8a50a0159eec9372026dc073174dba917c013e7e0751c19e58fb1e7f86fcca485b2e96d2933096ae400986b9daca0805a7096a6c63e7873b66f6f49c055000000000022d149d0fb4e1ffc0006567a01fc0006c05c01fc000bd4aa00f2ccd30a71c62243bc1b85b0a7346be5b0365febf2ccd30a71c62243bc1b85b0a7346be5b0365feb1ec5c66e9789c655ae068d35088b4073345fe0b0308979c7c3f2f5778e536fa1136af3a024021cd7be5c6dcfc2d51e84091783a5b512b7f6a2c5851be08437be08d17199f1000000004ac3d41c3b2fb88c4e4c33b465ec1150b43522985fe221f18c4b91b5f7b43cdf0000204ac3d41c3b2fb88c4e4c33b465ec1150b43522985fe221f18c4b91b5f7b43cdf207523a0aad3ec9005879e0066cc09b41e57f3b9fd6110f99de7d485ad8f1f192b0143c1ba3eb8658a4a88acfc9842eef008612bb8a242c8000000b93e96c3fb2711fc000152b90001fc000155c4009b977ce8fb19c58e12c2da268990d358df102721208d9e4d63aa7667b7b67bebf81d9e58e2f4d464b88b7859dca0971128eca01438c8a22d7ff13b5f308ebffc014c8b97d9da8841464d3c7cd09b9f679471a068666c217ec13524ad7ccafa50eb18126c99edcb43fb74e290b901b88b7859dca0971128eca01438c8a22d7ff13b5f0000004ba9ca59a188bca15df2ede79db16e72f427d2f8b6f6786d82d4c64319411e230000204ba9ca59a188bca15df2ede79db16e72f427d2f8b6f6786d82d4c64319411e2320a9fee48733f80aec8d5fa07e467748169501c42f39b051f970827b977e4c68c501f74cd1f9e2fa05c4244dd2489fc836825e9f10d800000000000343bb9bfb4e1ffc000b2b630001fc000b2d1b00dc02c3b908e77a84a09427aaaf15c5256f5b458e1f69134183fab7568ebf7eef6c97f80b3ed603aeab2f3158075540dbf499033592d803e7fa3675a2308b7381340a3e266498248137c146a3c82e36c27c196bac05772dd7b22132912bcfdc1263e2761245b6871b47dba982a6000000004bba47ad7330a358cafe2890f1578f874006a68bdc7b786a7c1d440823e683d40001204bba47ad7330a358cafe2890f1578f874006a68bdc7b786a7c1d440823e683d420ca7dbad69767b30fe851c08c80df2cc8398bcc8c33df2d03bcb810485f3d8d31006e6c9189021b6e38326dff6886104054a110990d00000000005fd916b6fb4e1ffc0010871f0001fc0010874300bd8b7dede4dab5e22b84ee0f3dace1c1021add92c9924137fa318dbfca7cabf3a1127fc358acc74d6e6c9189021b6e38326dff6886104054a110990d308ebfddfa72f3140798b6c0d89190164c4dc569ffdd95bd1dd43e7f54f1405c1927b37b499623b4c806ea396bea40a84d0001b98306c317875b12fae8a85c85eb23269168981801fb682301fb01c14d13a8912d3119f1a9eea95d70a546bc449307af3521dd532c0ecb1ee5a494d70000204d13a8912d3119f1a9eea95d70a546bc449307af3521dd532c0ecb1ee5a494d7203df27e67f50cb6875d7b692c594939cf46afb84f80c3a483181a3235532c325a01c329e938e558a6f1a348468050a6a0a48f8468d1000000000036c8c8e4fb4e1ffb66b70001fb69fa00e855484a6e6f72f6f4793b80cafc202a981fe8c1e855484a6e6f72f6f4793b80cafc202a981fe8c14fc445e107964acb8baf2e91cc87acc92ec7fa6c3009ca23af93ce00a95bfefe790ffca791e093a8c0e79675b103b2a4d06f930433b3f6b15c83f4e2c4b5118fe0c27ca13a000000004d159f983d445130fff5ade93b05e01172ee4c56ee3c5b252277615ac10c4c8f0000204d159f983d445130fff5ade93b05e01172ee4c56ee3c5b252277615ac10c4c8f20313e02ee0e20e1cdbca93d89490c8c9caaba06e6558670cacd259f1c8814007b01e0464a5d60141aeb8650b95a88f576c86ad8230200000000003425a9c4fb4e1ffc000bb3b40001fc000bd23300f062a34a0fb6489242d4679a98a4b853087d6903f062a34a0fb6489242d4679a98a4b853087d69031ec5c66e9789c655ae068d35088b4073345fe0b030848d62d66f87f7de6ad828ffbfbd1432dbc983ce86bba885cabf1114835f6de4614d3cf293d6daa92d98e5e1ca36d26e000000004d5087a16a45ee3434db18ba9be18b627794ea9fcc2ade4411ab0745c587c16a0000204d5087a16a45ee3434db18ba9be18b627794ea9fcc2ade4411ab0745c587c16a20486494877c77a3dd5d80aea481a1dd6821d00eb7785d7c5b0646dfe9cc7c01b901a610254a55a28d50033f2df6b34baf904c3132e3000000000041152056fb4e1ffc000c329401fc000cc8b801fc000ce9c300336788df1ce1418edfb0b8321db1611264010a7b336788df1ce1418edfb0b8321db1611264010a7b7ad529c7f0f78a1f5a4ee5c4f8855dad34d7c535308162401aae703d5bb3f53a7b9c5b65b9a94dbd1c207a8da8f1350200a960d1607e89e50b365afb14cf3b700662342a4c000000004d5fe9da329316db465fb3f4925cd5604dd61335c32f0b7d79bdcc98e71880d20000204d5fe9da329316db465fb3f4925cd5604dd61335c32f0b7d79bdcc98e71880d220a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e50a4cbeb2381d842c9d9e0221395627f391d1581a200000000003422fad6fb4e1ffc000ccadd0000004bd7db8a067386d8bda99986fd6661186757bf954bd7db8a067386d8bda99986fd6661186757bf9564f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d73087be789e5b798cf3a40ff5dc22b0384dc690acadd614067c0f7e6a933b8f0c72c67b3f4b3e666e6fc48369a8161b04e6000000004e440fd1740b4ad578af9d5f11667830eaf8f422898c00d891e3f3cd075ea6130000204e440fd1740b4ad578af9d5f11667830eaf8f422898c00d891e3f3cd075ea61320b1e914db9a6663500db9ff75eba0c6717a9fec4abd9abe995897ca5cd84ec20e00beb09ba540e70a97843006e392a012cb8cbdc70900000000005fd916b6fb4e19fc00108b3f0001fc00108b7b000586047cd6cfc021d742ed07f331cc5e41b6b76d21be19b26057cba9acdd22fabf0d3643e8440b65beb09ba540e70a97843006e392a012cb8cbdc7093090e7cc61a596c1cae0c431f22e92ad1ea142558e6e2fdfd8cba033040a4bc56e58f44ccb3380d10ce89246fb6f1c52bb000000004ee1227ac0f4be1fe27ec0d00601287cbcd3182d3b10db952fec225d68f717b90000204ee1227ac0f4be1fe27ec0d00601287cbcd3182d3b10db952fec225d68f717b920037c32c262a9f798855661033c70a485c9efbab9379458ebd2bc3dce1f2cbf48011f6a174996c5075c827596ea0bfc10a97a071dd100000000010000000000000000000000000000000000fc00067ac70001fc00067af3016398e2e031739ca5378d8b64d33340a99d1317260258f7afa5a4ec575f6781fb2d91fd59f8a409d63e28db34964d56b44c53996dd85877e69c9453ef30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004f4cdd55a71a68183cd6ceb8da6e95c9526e259ce0d243e297ecbeaae0f93ef70000204f4cdd55a71a68183cd6ceb8da6e95c9526e259ce0d243e297ecbeaae0f93ef720b711c40f6d1eb02fff2b03c35a759fa63b3eedc2b47e59191b7e1d0353b814cd0072235a751c82d0d01ab336190bdfd4eceebf4a6e0000000000b23e5de2fb4e1ffc00022f9b01fc000266ac01fc00052bcb00a97f2ca1f2953b0ad3dbc58b12fde33f39a4fbeee0cabfbceeb716b5b558739f218f9516c16918d272235a751c82d0d01ab336190bdfd4eceebf4a6e3093a5eb4a6fb84c13bba4d597a6f9d37f565048a384c94d3b81630c6965a023eb3748b6fed0ebc224f051eb23f50d9ff300000000500bde7398a2ef46b93994f34d3607875321076ee3ef975d5477c3d06b0c1659000020500bde7398a2ef46b93994f34d3607875321076ee3ef975d5477c3d06b0c1659200a73fb35537392612450d065440abe6b192373607da402843c78ceddccb3cca201f958e2271fac8498a057a0f4715f46ecae3993bd0000000000a763b737fb4e1ffc00051ba001fc00052fc601fc00053183003a442deb895344b8c98d1f96db46d73aec73149334e4669b580af3248979acd2db51c30d0794c76ef958e2271fac8498a057a0f4715f46ecae3993bd30822967c827427a4ea722459a6a5d007c5a14e1da4b6fd52417914cdac7dfbc9233dd046cda0c2980d1936cfa8b22920000000000507e64b697d351d57308e00312cb269564502e07fb3a05c501952de3972f059a000020507e64b697d351d57308e00312cb269564502e07fb3a05c501952de3972f059a2034fe0ea681d38ede04970088cdd82161c09e03c24f08d62c08bbecfcdc62ec1b00979be1258712fc0292ed17304a2aa2f05ae762e6000000000036cb2ac0fb4e1ffc000bb3b40001fc000bc79c00491b2884357e499e86dad5fc363b951305570ace491b2884357e499e86dad5fc363b951305570ace1ec5c66e9789c655ae068d35088b4073345fe0b03081baf71805fd63ca4357d12c6b77cd04b70846abd99d8dfa9e8b4469c2d167909399b2efcb32ec817e7fe75324151c080000000051172935cfc699e312ec12338e14d12fd54a5fb4065922055980d8206ded70ec00002051172935cfc699e312ec12338e14d12fd54a5fb4065922055980d8206ded70ec20ca564761a2aae2a77d104426a7843a92995d2d94f7e951d792bb78fc22be0d5c00636bf0d4a97d772962f96c66675629bd3e6578ff000000000022d0be82fb4e1ffc0006567a0001fc000bdc2300587cd605573d22f879d8f02b4fc6901ffa1ce1df587cd605573d22f879d8f02b4fc6901ffa1ce1df1ec5c66e9789c655ae068d35088b4073345fe0b03005e41c9c5f3e90a39f01b6a6723d505378fb3a25e19c0b7915303a1e7da89a19ed0a1c5ea765a6ed2efb3710de56f19b0000000051238bb9e2b68fc822e8eb15d415e97ebc86f769a72c15e0a6e25d9ea8d3847500002051238bb9e2b68fc822e8eb15d415e97ebc86f769a72c15e0a6e25d9ea8d384752073663de296744bdf1a11ef3f43d64e249644ea7499e54a8848baed56d716fc3e002b7856de53d4c1823090c98f8ad79862842c09b54120000000b23ecbf9fb4e1ffc0006b1f900000091448a07a2696b4d310761442aa07e3f2021cb731341a33990289395b5659a4cb30cc07ba002b505288e0340106fb37e4cba12e21c2af87e965ebb8b30ace65ce6933fbafc8686ea9e8ba72bc98f3d07905b4ccfb83162db440308e9255f708ce4f2623b27f9fc04fe11cf605700000000518ebe3158701e981095522cab5941883e56240c8ce9ddd79247fc5efa00af3d000020518ebe3158701e981095522cab5941883e56240c8ce9ddd79247fc5efa00af3d20a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e162ad150d5b108c42779d7e62869b5c32c2352498b000000000022dc764ffb4e1ffc000ccadd00000081a5a6e113fbb398b5dd1a3817a4cd66b955b58881a5a6e113fbb398b5dd1a3817a4cd66b955b58864f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d73096594c4eedb5183b0a4e1e96e45bbe8a042904abea4ece4619cc4c3c70073036adb8eb9130a672481eef6a2143b8761c00000000520c7377bf695cde36a0dc0ddd9aea060ce4a4cdce59022e7d74f501e5fa71c0000020520c7377bf695cde36a0dc0ddd9aea060ce4a4cdce59022e7d74f501e5fa71c020a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e62dab139056dee908016c56f7676e18f04666c4937000000000036bf9289fb4e1ffc000ccadd00000033fe2817ece26659df352c7abdf87f8cb7dde58b33fe2817ece26659df352c7abdf87f8cb7dde58b64f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d730842d732a03847819b1e2675ac48b9af4a1c92b310ecacc42c428ff902099cc47d08ecd4616da55d185463855aee99f7900000000521e7d6a4b937cb19dc62371436f1805c2337a772a5e3884097088b23cb39c9a000020521e7d6a4b937cb19dc62371436f1805c2337a772a5e3884097088b23cb39c9a2016bfb58979d90f27253d7a052b620631266a3f35e1e46fc40ff6481f2acebe40000ba3bc9b96c628693877db3bfeebe29b3ac1b1ae000000000023596403fb4e1ffc000bb3b40001fc000bc76b000fe161af74ed12af85556bae73fd1d3af6a01ea40fe161af74ed12af85556bae73fd1d3af6a01ea41ec5c66e9789c655ae068d35088b4073345fe0b0308d51215f8e1c1f68fc8db92517650a76251c8ee8800de92b97c7f4d29c50eda699c82a7f671b597eb52fe08cad760d6400000000528b059c0430be26babd893fce8850ef5f10ba1b166331aa66de0f58f1bd5cb9000020528b059c0430be26babd893fce8850ef5f10ba1b166331aa66de0f58f1bd5cb920778ce40a708f33b1ed5239b14edeae85497eef97146cbbb8ca62b37873abdb07002300d33f550b325773744b9f8843a65151388644000000000022d1a62afb4e1ffc0006567a0001fc000bd983009678d36b05e068a7aefc08edf11353d6db33253d9678d36b05e068a7aefc08edf11353d6db33253d1ec5c66e9789c655ae068d35088b4073345fe0b03080a3e42e4ef0c3f27fcc7b70edb253590af1ae9865bc936210f0b68f8e7c0690b6ba65daec04e9da61da85ec8865244f000000005346dd62f6d0d846ca8b37cad7e4438d1effa1a61a63f8d55ba93069f560949b0000205346dd62f6d0d846ca8b37cad7e4438d1effa1a61a63f8d55ba93069f560949b20ef27728a1bfbf13abcf7420e3118cae96ca0184ff1d0a796b90c51a543202b0001a01a6124dd32d31434325f8b39e3133ca643b8c3000000000034348bbafb4e1ffc00013b0a01fc00014e4301fc0001517300692ac6d2aff4da4de4a815b41b58369de627380f692ac6d2aff4da4de4a815b41b58369de627380f69a9e3015032f43608f55847cfac26a1926ace9b30847178ed08f0f5728dfe39ba9e3a43555b4c5e8100d825d91bf452bb7dad7bce7e8224fb665abc59cfc74d3bd1e040e10000000053572db6934dd429546362bd33dd18aed1a49b96dd9a8bf0ce1936975991b6b200002053572db6934dd429546362bd33dd18aed1a49b96dd9a8bf0ce1936975991b6b220b2b69159973619cef08b9add969ba4d1ae18dd33bd62635429d44d93b62d5753013ee3c4a4a092ba275cdff0c03b912eb1d83c5e8c0000000000ae22e975fb4e1ffc000cf13c0001fc000cf6cb000d432b7c544c11176c8b543613cc395f4b1bbcf8ce7f101b7f075273c892063b1b8571311737a5767f95c0f808aff27883260bfaf9cfe2b84519a6b23007f818e5c2330ac4e7f0ef820f337addf8ab28b07c9d451304d807feda1d764c7074bccbbd941284b0d0276a96cf5e7f0000000053bb55e972ab4f796aae8c7eed34d09adc55241edeead6c7171c2ada2769c68f00002053bb55e972ab4f796aae8c7eed34d09adc55241edeead6c7171c2ada2769c68f208230f90a0fa0e758f70dcee360ab25c46f3c43e674fe277b60ca7764c5f420840076e959b03bac123bf2ced68c6705fe4fd4e280f441700000002269201dfb4e1ffc0008836d0001fc0008844b00df18a921f89745939ee3f00b9dfc07a167f4061fc291f09365d25227523575b9f07683a28c205a30de9aea4685986edd2c37ee8a3245d8886e63fc663008af8fcaaef14df7bc8ddfae8fbcb1f239040be0ac89d43ce0f27ea3f7a00d1685ffc1075614144e70f02df385a996f7000000005557273f5922d9925e2327908ddb128bcf8e055a04d86e23431809bedd0770600000205557273f5922d9925e2327908ddb128bcf8e055a04d86e23431809bedd0770602011980a810803e9264875774c7b736eafc40e3c0c6d86b719f2e54143874d0299011485ab410c60ed103eb5a0bae666add00978a88140a00000005fde193cfb4e1dfc0004a2b30001fc0004a34c00b0e606ec0ec732170fada5204ef8ef5d1dcf73948fd1a9502c58ab103792693e951bf39f10ee46a9cb4b5cb5765cfbfbc3ae17aeb48f8533bd5391ee3008b66151b81bd6a08bad2e68810ea07014012d6d804859219958a7fbc293689aa902bd0cd6db7a4699c9e88a4ae8c2c00000000055cd64d8a3d53fde1faeb46de639a7478b4559aa9040d37b2b19a28a7c029cf100002055cd64d8a3d53fde1faeb46de639a7478b4559aa9040d37b2b19a28a7c029cf12071f2bf95b4d52ba83c2fac722efd30723f3e99ccd83849006df4045760bc919e002e7e345d77cab6d1ec5e81f17b98f1e4d0ebc4984120000000c1758ec8fb4e1ffc000ac3160001fc000ac34300d2f955d617b4c5687619d9030ff1b9bc39a7fb4ad2f955d617b4c5687619d9030ff1b9bc39a7fb4abb42031cbd012787b56d53dff7a46c1d0b66ff77300a1442ae1b122649814bd8354b4daee4a289220eea514988d6cc93ec6302e346bdc77236c91967ff86362d81b18b1c7c00000000568a820b27ca755a2dbd072d68d0a8bb19ff486b472aca350290ca30ac7a934d000020568a820b27ca755a2dbd072d68d0a8bb19ff486b472aca350290ca30ac7a934d204d937aac30ca900235ca2a476b48ff19bba8d0682d07bd2d5a75ca270b828a5601ae69c3808753ea7dd0e2e3d1565ded12d8eadb9e000000000004030201fb4e1ffc0007581001fc0007586401fc000758930094c7496c719925d805ad2f0a75c837fd9abc52c794c7496c719925d805ad2f0a75c837fd9abc52c754de5d26228df57289545787fa448a7c9f7ebe2c30983bd995f3e1280858f37e33edabbd8ca4d90605e26cb6dce824a2c03f83dd498180085db4168f9e6b4df0b46a7f4f54000000005725d47a054dc1b4d34f719c4f9a5a75b52f08b59b0ba5ad788c1e29bbca0ca50000205725d47a054dc1b4d34f719c4f9a5a75b52f08b59b0ba5ad788c1e29bbca0ca5200e2bea11a7d2fa54cfab488d4cb0e7e5c28d8fb1f17b89b3a5346bdec9b53fd900e4f9a674bedaa1272b51355d8efad13d6fe7653f000000000036bb2f47fb4e1ffc000bb3b40001fc000bcb8b00482738ebae2e214d55bbcd03d7d0e81a7130f955482738ebae2e214d55bbcd03d7d0e81a7130f9551ec5c66e9789c655ae068d35088b4073345fe0b0308397590e589e42728f349a499466c06a7dbc797a07787b79145d6e18ef9859e0b07e64a665a3e1c2b54663ee8dca6bd500000000574a8a1c55a14ef27fbc1cbc52545d9e94944984c1201fba3aeacc309a63660b000020574a8a1c55a14ef27fbc1cbc52545d9e94944984c1201fba3aeacc309a63660b205fd493a731389488c69e721fbe31f8996395311728f8393c97648970b1c3f0af0033cfb3f4008a512c56a47174b23d40700065161700000000003422e1c6fb4e1ffc000bb3b40001fc000bce1300175b30c912de7bbb1a71fb1766ca91eaaab6e8b0175b30c912de7bbb1a71fb1766ca91eaaab6e8b01ec5c66e9789c655ae068d35088b4073345fe0b03009637af6c8533b5329eee8457477bf89386af20149a7f4ad3a76dc74876907cae2672324e816d70b9160e27e335f1bc0000000005855f045dc4db4213f0bd153adf6ce3a02e59a06a3887cf01ff552f81e580cc10000205855f045dc4db4213f0bd153adf6ce3a02e59a06a3887cf01ff552f81e580cc120e75569a4dfbbd1fd45e5f54f03642caba755b5ff7d1e2919f71c069cdb9266d90012da5021d6ab01854ecf7510d834d6ae89cead96000000000012edcc99fb4e1ffc000656800001fc000bd4aa005b7fffe5a92fb181e91ab6fa5cbdff30266c86d25b7fffe5a92fb181e91ab6fa5cbdff30266c86d21ec5c66e9789c655ae068d35088b4073345fe0b03018ea4f800b55d185f2abf9b0df7aee48cdca7089178e1b1ed212f2b561eb2f66d638c64e9a3dec12490c04a4deac6faf00000000585674740dac63692bbb0ea4ee899c575f9883e91fb5ba5ebf26b5b2fb66f21b000020585674740dac63692bbb0ea4ee899c575f9883e91fb5ba5ebf26b5b2fb66f21b202bba3595a323203f3baaf14c9e656a2db305b371f974fd2c08d63559dcb356380181949e154a2d3e19abaadccd78998f419f86075e000000000034dc8558fb4e1ffc00012b5f0001fc0001305c00c1eab1a29d98db4b44708a6db97dfeae5fb123c60e03a8899ae0f3a5771fa41ee75752713e920fd85aad5c1b35da17982597334b504c22752cd6319e3093dac0f5d028eeddeaf4257919511991872523675ab24d1d971af3ab1900f27fc617d1d53a846c32abe1ef52a2cb26ee0000000058eac04dafeed9c30b3397c527714c273323fa036a0ccfe5aa71d5c4fdcc270800002058eac04dafeed9c30b3397c527714c273323fa036a0ccfe5aa71d5c4fdcc2708205529d4297a7587a2a915070b9b6f53eacdb4350d118e5af99b6a2abc8b500029005127e6f29037d8849f2a3be369dd9989e383016d00000000000b7a212cfb4e1ffc000607b20001fc0006087b0044c8afafbb5c35b797e7a8876f8932829f99c6c044c8afafbb5c35b797e7a8876f8932829f99c6c05127e6f29037d8849f2a3be369dd9989e383016d30046e3d8efdf54e1cf182c8eb894c4bc1a2845fd3e8e20a383a80435dd131e34e69ee562cc7f31628960e1ad57fdc538a0000000059d45830e45260a043fdd196f966679f1a63f1b6c28f04563738226bd654865800002059d45830e45260a043fdd196f966679f1a63f1b6c28f04563738226bd654865820a042308e7ee24af38a5afdd588c33e007a0ff9168bc6cdbd7ad29836488c64c6006b4ca496710b456df19d9f8f7bbda99d4a9bbfe4000000000036da68c2fb4e1ffc0006567a0001fc000bd99b00717fb4495269642bdd0e16cbc60d15e31a2802aa717fb4495269642bdd0e16cbc60d15e31a2802aa1ec5c66e9789c655ae068d35088b4073345fe0b0308ba4d80404dae1a9a1b3aa7bb7173ba161b87f3212cc4566bc22ff9cb1253376d8f9edfaab3db702a32741b1bd902016000000005a5b3a5da96d5ee8ec30e9cfe76cf0c407ef040836d2dcedd94c4315c9f07b590000205a5b3a5da96d5ee8ec30e9cfe76cf0c407ef040836d2dcedd94c4315c9f07b5920597bf0c915434cd9eddcd2360804ef07c4f06ce7cfe930ece85e6da95d3a5b5a016cc8146b2b970595fbf4e267afcfc3212002584c410000000012de6f46fb4e1ffc0005418b0001fc000543b40010b27fac0d3106227397fb1cb91eabba630c0a31f0c742302a89db49217e328e18811d0ab1904ac5da952b3b45775c0af85fbe2e2ab21549d86beb0a3080f8dfef131ac329d428504e7cb89974f188f07caef0668df1daa4ca8fc5f50f6c5945f020271292dc220ce313c00f16000000005a608427d3cb472597fe47ed7f9c4b430961bff0e7fd3bbe3a4553375cf2e4ab0000205a608427d3cb472597fe47ed7f9c4b430961bff0e7fd3bbe3a4553375cf2e4ab20abe4f25c3753453abe3bfde7f0bf6109434b9c7fed47fe972547cbd32784605a01118b5a615cdde7e435bb8bd1ee15a7f4c490d21e0000000000ae22e977fb4e1ffc000c225301fc000cf06701fc000cf6cb00c1ad3af209f75deaeb9216fc8339fd48d376f9b0ce7f101b7f075273c892063b1b8571311737a5767f95c0f808aff27883260bfaf9cfe2b84519a6b2308a0ede82d78a0a8f4c2332d431c7be496c3aa09349ed3b2db30f7eb7dcc7b6e580a9d71f7d76bdaca1b3670e0cf4cd3c000000005a6d674367f4fad9883595d74d6eb628c59495a3af0732d24db983359cb7127f0000205a6d674367f4fad9883595d74d6eb628c59495a3af0732d24db983359cb7127f20de14b280405beaa7359475326e337d7fe322e550a612c188c8c33f1ec05ffc7a01b1ec17072d731ed30edac35422f49fc43c6117d50000000000b9c313d4fb4e1ffb89660001fb89da00a6c4b0ce143aed43b6665e086fdabc05f6797a2aa6c4b0ce143aed43b6665e086fdabc05f6797a2a486c5d35a36a1cc86cb1c8946be6c3095b79a544308f53fb19c3be85ce00e96d634221f20a06a3a50942998193004264075a70422a3305f57c0c478a70ad69f1112e2f9993000000005b246080ba64350685fe302d3d790f5bb238cb619920d46230c844f079944a230001205b246080ba64350685fe302d3d790f5bb238cb619920d46230c844f079944a2320774441a2d4ff6133747a8bb1b5e4a9a21bb73c4b77cf31e85bda68f898949db0013f978f2c099e310cac9e854b99bc981c8fdcade2000000000023a5327efb4e1ffc000cfb4d000000ebb7d8141ecbdf2abcdc3ebe25420b9425745293ebb7d8141ecbdf2abcdc3ebe25420b9425745293c69a0bda7daaae481be8def95e5f347a1d00a4b430b44cee83a79fa151527e527f3f4f5ba022e73ae8b0d913c4185a45c2a129aef935a585a7a725edcb36ece72a957586880001f460a07a2b0dc932e1d8ff2dee2b984ac415dceb01fb8f3001fb05a35b5e74eaa81cf214241dc38fda186e7782243b77f112bd61c3e4e83f49f27a270000205b5e74eaa81cf214241dc38fda186e7782243b77f112bd61c3e4e83f49f27a27201059a0d6de258ea8455e3b995cfc62aa2773a3bafd6e1fcc00e9c4c5b8bb9a7d01433d10cc55f8c79b2dc5909099ee24ae9d3f56590000000000037c8ecdfb34a1fc000d6e440001fc000d6e9b001c2ce317e6977a829188866e9d4f82b53b82ac0c90d6c5ee0763ec84de95ae93cdabd1155d9d8f4e972364013299903de8c3a8c504669542ce20fd04308119fe1f9f05f7222f62c4b22a05880a89e4d8b3b8fd3011661df80e46da3ccb2222598129e3e67998883ede2bfe1143000000005be5a28138a658a802a1e871d7bb4a5e8a167effe9e665b4a2ecaa559d01734e0000205be5a28138a658a802a1e871d7bb4a5e8a167effe9e665b4a2ecaa559d01734e20439873740ad2b64a21becf94198b3d570250c8230b4a0ece9e0b78a9035c189b0096fee7f21ab31bda8471cec48b23e87b029d42d7000000000022de6689fb4e1ffc0006567a0001fc000bdbf30028a6d0e9738eb5ac91e4e5e5e715f0b16631396728a6d0e9738eb5ac91e4e5e5e715f0b1663139671ec5c66e9789c655ae068d35088b4073345fe0b0300dd55240db07aa6079e3b84af0d86acf307411f6a99d9570eebec93b6e7e5890db40e31efdca4d5d7bcee1f105e80ea4000000005c6542766615387183715d958a925552472f93335fa1612880423e4bbdaef4360001205c6542766615387183715d958a925552472f93335fa1612880423e4bbdaef43620593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c0f62555d44fc8d089674bab5d090a48825bea701b700000000002cef2799fb4e1ffc000cf99e0000007ef7c15840f96c603fcd29409a70f77f878d25d87ef7c15840f96c603fcd29409a70f77f878d25d8c69a0bda7daaae481be8def95e5f347a1d00a4b43086d0a2ca6f434eaa47ff6919ecafa4fc3b012b89c62a04835a24c00faf62c3d30d3f8755c33a7abc595e96fb5b79594a0001972a33056d57359de8acfa4fb8b29dc1c14f76b801fb8f3001fb05a35c6d5b4d2567346b2ada40d2dabbc907cf8a53c352593333e7d1fa8a635572080000205c6d5b4d2567346b2ada40d2dabbc907cf8a53c352593333e7d1fa8a63557208205b016215386c035a42042a93736befccdb87c30cb90adc3b1279da58ac57cc14046094547209833dca44803c3a5b039a038be4034c000000000012eddee4fb4e1ffc000cf8b101fc000cf93501fc000cf95300bfa25fb4ed44c385e69d5d8369a0a7b90d68b4f7bfa25fb4ed44c385e69d5d8369a0a7b90d68b4f7c69a0bda7daaae481be8def95e5f347a1d00a4b43096f1efdb9fbe12961b7f113de6a5e57e6f547a3b27b4b8941a5265ddc51de7b6dfa7eb52ef96fef6503b4a729884ef12000000005cd86ed16f87819dca7b6e4e3d24947b1a6328ed8cc4c9aec7af35fa2b1622200000205cd86ed16f87819dca7b6e4e3d24947b1a6328ed8cc4c9aec7af35fa2b16222020fbae7f5db70dfecd69081854b27514ec0b29f4bab86717174e0220bd7bb9584700b9dd1b5f9c18e8260fd7e7f9f1d9503709f9168b000000000044b7a710fb4e1ffbc4230001fc000195cc0025c8d7361af14d912026940701c3d5d440ae6913069efe06c4c2d7ac2a8c61f961f686a13423467cb2334b22379811352d9988876a6e586d975e73293018af4d035eed23d30eb02808af0c133d9879c0fb82c72329ab2ed208ebc1631641ca42bbf462239d151f4e84d8dcde7b000000005d49c93481f99c7e1d85cde715697762973d9c49d6facf50131e11b2c14c78130000205d49c93481f99c7e1d85cde715697762973d9c49d6facf50131e11b2c14c781320a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e1120959bed4177d7abcdbb412bd8b8e1f920bb623a000000000022d93a9efb4e1ffc000ccadd000000079a7d38b11c6a3e040e4e665150768b8a5faec4079a7d38b11c6a3e040e4e665150768b8a5faec464f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d730826cbf63d989916d252cfc2cf827f34314c32c64acc0c252f1c3d42019589650c3ecb098655ba153dbc04211a1a73e88000000005d906997d8b370d37f813ed55c664457fc98acabfbf5e5602952f710b54bd4e50000205d906997d8b370d37f813ed55c664457fc98acabfbf5e5602952f710b54bd4e520a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e3d6ca51bdcb6817cb4f722a45a7646fa5070ee902800000000002357ee76fb4e1ffc000ccadd000000431c84baf52eb97d5546ed1ee44872c30772a30a431c84baf52eb97d5546ed1ee44872c30772a30a64f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d730155b2a1aa71cbb3b5fc81b00242805a6d573826679a2b6a5c49bec714829322efe8af0c1640ba3b59811c70e17b488a5000000005dbd3e1adcef3a9e61ea1c8d0d3bed643ab3a36872ad78905b009cd6dbde6df50000205dbd3e1adcef3a9e61ea1c8d0d3bed643ab3a36872ad78905b009cd6dbde6df5208e8e515f7025352e7c608479e413beacf0d95cbb964b47e4a98fd27b6b6b628a275615f5efe0555e81f7799ff3e1017eed0f5d8160000000000034d41347fb65a7fc0005e6990001fc0006579c00d0a7d804064376431fc57385721270a55fd99154d0a7d804064376431fc57385721270a55fd991545615f5efe0555e81f7799ff3e1017eed0f5d816030119d599048331efb5bd38ea0506ac51765eaddf396114dcf14fbbbab70b7a929c9227f8ec980851ad79f502d2fd1750a000000005dd021fc25cffa8a8fcc138726d3771d7a11ed67826ef92f8cce1deeeb8994cd0000205dd021fc25cffa8a8fcc138726d3771d7a11ed67826ef92f8cce1deeeb8994cd207d3a61ee47e7406247f3c530c94eca04fb61215407084d494fe341e0bd6e6dfb00e64dbdd97978ca06825948e22965eaf261f75e3e0000000000b2077c28fb4e1ffc000732760001fc00073283006d40952f2f57e3d63ad144d4171de75dbad6871c6d40952f2f57e3d63ad144d4171de75dbad6871c3b8fed059edc3b85af8bc75de109566b89aef260300cacf46c91a350240272bcf66d48eafd77c78ab71185ca41769621116c8dae8b29732fb998cb6547f3fb27b556c660ed000000005f8457a7640a8e99840193865a971146d9e25a97d8dfd6f0f1f73b18fd962c440000205f8457a7640a8e99840193865a971146d9e25a97d8dfd6f0f1f73b18fd962c4420e77f5d18d3565f6130ef095290517a91b9591ae927defeafd6875daade6ee39601609b88d96948cb06b59241d773a085b72f416caf3f80000000b951a487fb4e1ffc0007d1f4000000d45e1d0d83cae06f0c68b0dfba62807d59214bc0fbe729266f43adfcdf3ede4f478c7a0ef915cd460d5bcbeeb459af40f97fcb4a98e9d1ed13e904c83097d5f022c3b6c314bde5171ead1616e4c27f0e9a48a9a9dc3a7227a62d42213b93c8a4c32af18bd8ff931b7732782e0901c623e2d926af5eb52dcc2b931993d3e5271451180000006029fadf3355a31c6f841570e76bcdf5636378c65ff1da8f580806602752694b0001206029fadf3355a31c6f841570e76bcdf5636378c65ff1da8f580806602752694b203e14ea3daa62c03d9ed56e8895b5d98188711c49818cd0add43d37fe512c93d1012a5d83dcce0edae361a62d8bc2a308a87e29a49b000000000059a9ab6afb4e1ffc001079fe01fc00107c0e01fc00108203001119c437dbe2c3aeb4a3c7d1e29380738e3372433e443eba6ce82ca15b203d10117c653f26944256cb505749178fb4f731643d9aa56c54e504f9cc6e30a4adf9fa35bc975e52e3f667e48ff3ed7ce71f8ecb85d5ec728596f7fee735c2f857fae1569c8b4c6839ca849cba42d1000197ed64c04be77ef571fd5624c0f7705192630e3a01fb8f3001fb05a36071df1e3bf80ba6cb9795bb2a82ef426cf559b7711e555af45fd8da7fb629b80001206071df1e3bf80ba6cb9795bb2a82ef426cf559b7711e555af45fd8da7fb629b820387368b816ed3599d758185ae60d943afc22201e94e06ffb3dad30a3ddc6756b0005ccc78c0358f7b71d254b28c7287da9b39b81f400000000002d20db70fb4e1ffc000d05b30001fc000d05cb00434dcdb7115427657cf2936248b62a97b9969795ff1266f2c8aa7b1f93a15b8882013af424d7d9e805ccc78c0358f7b71d254b28c7287da9b39b81f430b4e545a909b1916959139eaea845262b0aadec1c5cf555922bb6e6d1804343e6490428a382a0c01832fc70c50438fea6000152cdd176257544a263ecadb986ed72375589a8a401fb682001fb01bb610f8f8dd4cae7aec25116ce7104742254ec559baa67b27ab471ece2a2aa7803000020610f8f8dd4cae7aec25116ce7104742254ec559baa67b27ab471ece2a2aa780320a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e264345f7c30d3267da06c6f685ac42770abc5b0ab8000000000036ba9112fb4e1ffc000ccadd000000bec1b55112fe6dee11593a3ec19e9d7128555218bec1b55112fe6dee11593a3ec19e9d712855521864f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d73090ea47f22be1644834d8756793f2308f2c5b40afd16ebb98d29a3bd37e437990d4d5930ccfa56c1ea0b4e51d05a49f2300000000617d72f6941af02ef5f2ceaa2ac0315ed5db0979c45391398f74b0fadc100ca6000020617d72f6941af02ef5f2ceaa2ac0315ed5db0979c45391398f74b0fadc100ca620a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e69eaa58fb3c117406b24cb6bce3b818f582ea7647e000000000023587acafb4e1ffc000ccadd00000017acdf555cdcf9dec1b41f2b44511123917d299817acdf555cdcf9dec1b41f2b44511123917d299864f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d730067ec5f7cb5511ba2bf10aa09eac4107d76fd53edeb2fd94edef4555171dbe3ed7dc6cfe37b087390af61a6aa269182b0000000061d33f478933797be4de88353c7c2d843c21310f6d00f6eff31424a756ee7dfb00012061d33f478933797be4de88353c7c2d843c21310f6d00f6eff31424a756ee7dfb20593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c15888380d6096d829d6864cf6eec66812266839e0d0000000000340cb05afb4e1ffc000cf99e000000b5b414e1a68e36a25df214ac6eba35782a0437dab5b414e1a68e36a25df214ac6eba35782a0437dac69a0bda7daaae481be8def95e5f347a1d00a4b430a6a63376eb861bda6afa09e28e39ba40cdfb877ee6f9aace10eaccd4caafe8d9243f2f2c0ef982a0766347073cc199bb00017ada3e486409b39c94a0833c8d782f35bc24e96a01fb8f3001fb05a36213059ec1749bcbb42e7b0ee5205b88df03ea2fb1a73d6c4ee10c9d3de9345c0000206213059ec1749bcbb42e7b0ee5205b88df03ea2fb1a73d6c4ee10c9d3de9345c203ad8c08b05fcd0c0dd9cdd85ffceb21c25366f4f32b81f6a0cc009e774987154006d2ceb670b5e0484285fd83d0d13177f608641a5000000000055d1f304fb4e1ffc0010173e0001fc0010175300da8d49b6e91746c548bbd0de25fdb62bbed5b872a43561ee4583153f4b18ea92e8fdcb3a602e84fc482551fcc51ba10000202e7d6a7938cba1cd28ef3013b9b565d5772aeb5080dc5bdc91a319dc33b4a2fca52d3998d6561a043b51bca50eea4dd8e8510239af01fcd6312f050000000063115def57591ee9abad23b796cff8cf63b7c1e9878ab77ce8e354c38803501600002063115def57591ee9abad23b796cff8cf63b7c1e9878ab77ce8e354c38803501620c72e50fdd7acc0be5942e53d2e5a616f7e86c4b4ae675b8099e4f8a1caef049f0018d49a0f47500900fc886294ab346b7c02c7a9d800000000002d4db010fb4e20fc000374ad0001fc00037a330079cd5958432147b2cafde22aad47375e690a9a4d79cd5958432147b2cafde22aad47375e690a9a4d83ee938aaaf0e18dbe7bdf40e639fd2d2dc188d93002ede7bba4f6330aa85b22f2d20167cb529ac1334125ec439f873c0cd7d54e7c07b65bca725799f8292564af4296f0600000000063dc5ee3b0ae326b1d590c1253aceb6b50982721e6d8b20e862433a2a6438c6000002063dc5ee3b0ae326b1d590c1253aceb6b50982721e6d8b20e862433a2a6438c6020a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e6bee55061de10219326c570d2c39cd051ef00d2c5e0000000000235bc5dafb4e1ffc000ccadd000000b190542b5c7522f4db19e48033d17c34afd71845b190542b5c7522f4db19e48033d17c34afd7184564f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d73013f411bb160a34b3d8254e7c537e1300afed010d4a245e376b81d889020854fb999fe9cbb7430ddee0faf2fe5e711ebb0000000065d8d0b30932771009cd7f022fa796da3ef4c1268728843ba71b5ca8c6c4374a00002065d8d0b30932771009cd7f022fa796da3ef4c1268728843ba71b5ca8c6c4374a204a37c4c6a85c1ba73b84288726c1f43eda96a72f027fcd0910773209b3d0d86500bce5e6c41e6658bf2a5738b7fcac02c520e391be000000000023a155eafb4e1ffc000b942c0001fc000b9d53008e9431059fc57f8c0c1a9625506b80589feb7fd6faab53c3c104da464745c096b8c79c91f47b835ef9cdba10be63d3e13607d4f420bb6b8013af2f7d308b98c8e6620c7893f7c26acc50d4e335b74f9cc866019ff0b6af497407fd0ebdb33c2cba0a6f2c4ea9a8aee85f22bf5f000000006691b5981eb27314fdd2c2eedf58a0571da48ee074600449eb825c485a17ea7c0000206691b5981eb27314fdd2c2eedf58a0571da48ee074600449eb825c485a17ea7c20a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e13229a05ff3504b016eafada8216af6f4a4170e2b4000000000036bf1c2cfb4e1ffc000ccadd000000f719327671f37c8f4dca62dba332ba17ba42e7e2f719327671f37c8f4dca62dba332ba17ba42e7e264f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d73000a2e66a810493a91b5ed1a8ef8ac4be41543598f5b4765a6f5d6339078ab88030817dc9c9bdb60c7c7a02d7787d6f2e00000000672830015f3330a96d5aa74d43b6dd2f6896821d8caed7fdad6427c74b7a7e2c000020672830015f3330a96d5aa74d43b6dd2f6896821d8caed7fdad6427c74b7a7e2c208e8e515f7025352e7c608479e413beacf0d95cbb964b47e4a98fd27b6b6b628a4ac20bcbf3e1989bd3da763af41bfd39b45b130e11000000000034d41347fb65f3fc0005e6990001fc0006573c000fb0af93f68351ac5e92ff99c982c664da1697020fb0af93f68351ac5e92ff99c982c664da169702c20bcbf3e1989bd3da763af41bfd39b45b130e1130151436dee05a55afb36dfcc21afcd193ec0852d2f2b27d86f3ce8c05e7e4d4af4e0023d0089b0ef3d41bcdaf4556b1fe0000000067491f0cb0874d179d8ece6f3ff25f721b2eb016ab5768bfabdc5e6ca614aaf900002067491f0cb0874d179d8ece6f3ff25f721b2eb016ab5768bfabdc5e6ca614aaf9200b469b5bc9057f1869e277e9abc139e8a7fa9cbf98f3bf4592a740249834d5a001cf333b39b37c22e1bcbfb2cfb9e98e85c622f08200000000005bbe7d85fb1a0bfb4ab40001fb701200de6d2589b9cd1d134c8aee733d9ecf70a21d3347de6d2589b9cd1d134c8aee733d9ecf70a21d3347a618f8434a31c9d45afc5d99aa253bdf1319f9413091e633b72726091f58e3bd1ede3a21de66abb2456c2f669be8bdcf76f3ab76aa2d75f7d03cf2f7d5761ab15e62e006130000000067636d7c7516e0eba85e2950cfa2c4d14e89b0aeb6d1700cb1c9f1bfdb4bb8ec00002067636d7c7516e0eba85e2950cfa2c4d14e89b0aeb6d1700cb1c9f1bfdb4bb8ec20bf0cdd7af7085c9e845a46ffd4fb3f460b73ab18af5ab9d7c76c1a8f13f63f210029aebc9994e27800397664c85b8d7c3c19ab788000000000003427fc58fb4e1ffc000bb3b40001fc000bc79c00a32c3c54a801798f6c7e4e579dcca4d55b9f6ddfa32c3c54a801798f6c7e4e579dcca4d55b9f6ddf1ec5c66e9789c655ae068d35088b4073345fe0b030071b53468e6124803ed05bb4961177a9e5207744ce04e742c6397e70c3bab2c4161838ce8a7284a043f7d1ab1f18d025000000006802ed5074a42b84a99b5fb6da29d04c2c80e6c9dc437203acd698ade36c6eee0000206802ed5074a42b84a99b5fb6da29d04c2c80e6c9dc437203acd698ade36c6eee20ee6e6ce3ad98d6ac037243dcc9e6802c4cd029dab65f9ba9842ba47450ed026801eaf63db1bbed2ccc65ff8763bf9cabf44b8d6dce000000000022e09864fb4e1ffc00017ebb0001fc0001aa6c00c924a295c5c6c72c2a650224eaf345293a9c18050c5f490d930fd36cd578b0f71c053b488b42c4edf32bb66d6fdcd07b1268d21a3e021c9c95445293308d6bea256f36d8b92071b66fa64f4023737cbd1b5dac7c1c9bf514cae400c332a1091df0ba8cd007d641a92507d9cbbf00000000682b3e58e283081c51f2e8e7a7de5c7312a2e8074affaf389fafcc39c4805404000020682b3e58e283081c51f2e8e7a7de5c7312a2e8074affaf389fafcc39c48054042090e2875a5147dd4d0c167017ddc3050be5a0c8690348ceb20567f5f9b8dc55490144d0e04d397a70492557046f0416c70765363f6c000000000040c13ecefb4e1ffb1bde0001fb37d200f4aa6fd6b27d9649267b4ae48e3be5399c89d63af4aa6fd6b27d9649267b4ae48e3be5399c89d63ace33dbd25c0eca0572668b263e170a70de199dac3005f2269374676476f00068b7cb168d124b7b780a92e8564e18edf45d77497abd9debf186ee98001a0c9a6dfccbab7a0a0000000068512af99ba954cba495e96651a8d730880e21437a873fd9309b54ea9e3b53cc00012068512af99ba954cba495e96651a8d730880e21437a873fd9309b54ea9e3b53cc207459dbe6d9b1930f8d6bf4d0872b2ed6af58baa2f0effe608e6e2ab0c98c148501f30f8dc6c5b956089b30b3dc91867a3b72620b2f0000000000b92f8494fb4e1ffc000faa6501fc000fcdc401fc000fcdec0044b7348492de6612c17d0aff5a3f6fb5f338d57ab2f70938b1cfaba9eab8eee718a48f292e1d5180d86df99cea20e4fadf223310df529ce645f0db2330a28a648ac2b271105426f11a070d3f4854f812c3fd0241860afd511a7ac76e681210505ed41121b141e377a73faaedde0001e33c1f9be807b975c0f5e1c0e3c63175d9e55ea901fb8f3001fb05a368fa216e06d6eded3afecfe2c4b1320a20652972a006f85bc024d8f46dbe8d8800002068fa216e06d6eded3afecfe2c4b1320a20652972a006f85bc024d8f46dbe8d8820f526a08420ddb3e2613d4b76068f9ab4e1fddf144ed69a02e8db33eb66b653d601eda9e9c11e82f102204cff0c4002e701b3f5cd1100000000009f45480cfb4e1ffc000504b10001fc000514d40086e21949f0e591e8803504f5245bef823d701997f07b6cfed0116e02792156cfa9f595b52a3d87c82d08e955f84b217d4dde65a6519ab77800c7954730039715a9bc06634ab10b432e3a9d446d436b4584f65c19aef93c69d07802690df0b51d81da6ff9a8de1542c40edb0b1a00000000697c2c82e72c2adb8909de0659da51fd64cca28f8e3bda7edd8db0d0653d4e2f000020697c2c82e72c2adb8909de0659da51fd64cca28f8e3bda7edd8db0d0653d4e2f20dd94d2653996e56e93e922e2dee824f6bab41274f86b183fc7312eedb229840700840a5c486b762696e25eae2bc9ff85b0d44011f50000000000235c0934fb4e1ffc000bb3b40001fc000bcbaa006aa4bdc44241524d580524e2623576169a0ab5616aa4bdc44241524d580524e2623576169a0ab5611ec5c66e9789c655ae068d35088b4073345fe0b030947b7beffebce3bdee5bba609a5c4491711f9c8c42d25fa02ed7da12f2fd7342762ef913986f1df8cc13c0a4381d1e1d0000000069d69bae567a8184b2b254ca9a5c4b8732daef78788a3b722f931f74df08f9e400002069d69bae567a8184b2b254ca9a5c4b8732daef78788a3b722f931f74df08f9e420b90bf3823ec4c4c6b4e0283d7ddb9ec00f99797471d585a93c0cf29f9bc98fb000cdd609cf68a00b4c13b040736aca0237a41d3006000000000022d78201fb4e1ffc000bb3b40001fc000bcba3001e009a2934acb4c1bf40a84eb29cb251d18e8fb31e009a2934acb4c1bf40a84eb29cb251d18e8fb31ec5c66e9789c655ae068d35088b4073345fe0b03084c5c9186e0d8efb404f4806218c2a5bc711396f445c27b0cdc8d31246ac7cf42d4b38ffe62340570711e446651569cb0000000069f156c10220991da1f4e8d692a582ea686a028d532b037f29684610fdb60d2600002069f156c10220991da1f4e8d692a582ea686a028d532b037f29684610fdb60d26208e8e515f7025352e7c608479e413beacf0d95cbb964b47e4a98fd27b6b6b628a409a9ff9309062608aa8b3124cb264fd29810bfbe4000000000034d41347fb65e6fc0005e6990001fc000657240076a035432f549ce35f39ae28b45f19965340d82a76a035432f549ce35f39ae28b45f19965340d82a9a9ff9309062608aa8b3124cb264fd29810bfbe4308e72ce4ecb7e37c0ba5376c77ec364606b796eccd05d80583a36da42d57421c21d3ccc3b3105ab18f87901e03ce09a000000000069fea9883dea2a9a962965e56322afc4f22484c3289726708fc760110804abc900002069fea9883dea2a9a962965e56322afc4f22484c3289726708fc760110804abc920ae65c812772f699dfef8c267595bcd8989043245ffd5a478953f4ff6bafb6af401a7749b674b1a7a60ef4e659d00e285c83dffdeef000000000022e180e4fb4e1ffc000607e90001fc00062e5b002c191f6fe901a5475f2a87fc3aaa12502057e97cf573287084ca8cd1ca8ab21ff5436945022466c2c9d30aa841c8e37e16f8095f20aaeac9869d26d93018d5da073c85f04213bf2cbc10eaab55f3a2779c0f347e2fb9c869024f30afa57c7054ed6b69f2a03ce928bc9683ecad000000006bb76b085315ed584034979fc0df5d8c09abf056299dfbab264a82f57b7245ae0000206bb76b085315ed584034979fc0df5d8c09abf056299dfbab264a82f57b7245ae20a0fcf7abd47df5bc7389ce1562d3b36d08d13ccfce876241191ffc269a4ba76b00885df61c52dd658243170bcb804fd4437895c8c0000000000023a48665fb4e1ffc000bb3b40001fc000bc79c005fd714f8f797e38f44abc6bf6ee6a17a932b68e65fd714f8f797e38f44abc6bf6ee6a17a932b68e61ec5c66e9789c655ae068d35088b4073345fe0b0308552bfb82f92fc63648ab91ea38925f889da4e349a2fe50e07b06beb1d15668e0e6fcee57dd80ad932459dbe6c8ecbbb000000006c397ecdbcf1a9b5901d871dd908ecac4a132391989bbfe0f75251eddd6fa21a0000206c397ecdbcf1a9b5901d871dd908ecac4a132391989bbfe0f75251eddd6fa21a20741e45b4f21dcb9bc4c1395a714685c225b50ffffe403bc369da656127e31167001a63f648d47bd04707df3fdc4ebe860990625393000000000022de80e0fb4e1ffc000bb3b40001fc000bcba300fbcff1cbe6c28765f774e51a53601d2687c831c4fbcff1cbe6c28765f774e51a53601d2687c831c41ec5c66e9789c655ae068d35088b4073345fe0b0300befed2efcc28f3b82a25c59d2ae163d3940801f2ac4f36afbd372d6c1f6c02a8a5214a29aac39d2059ffe6ac8217925000000006cca50b04c9816b07a8a831ebec34866f1f0fe836047890dce4f1c46f9e8a3c00000206cca50b04c9816b07a8a831ebec34866f1f0fe836047890dce4f1c46f9e8a3c020a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e102031ace81ec2e17de17e57c69f3c3eead8334423000000000036bc4559fb4e1ffc000ccadd00000094d596c0f06812174b31eb104a44cb1c9456307394d596c0f06812174b31eb104a44cb1c9456307364f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d7300ad4f577d067630f6fd15f4d2aefdb9456d648b71cb7253d47511acc81dd5ddb69a03c848322aa11e5242f66afde5a2a000000006ced683bb70cfb82159b08d68a9b6bf2069b328e3bd028a441574fdbb0f9d9a70000206ced683bb70cfb82159b08d68a9b6bf2069b328e3bd028a441574fdbb0f9d9a720a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e5dcef7f4fc2d4474828e84e85ddaafe52f606d7a3f000000000022d7abedfb4e1ffc000ccadd000000ad8cd8652d70a94aed1d6802bcfe9858f7c8a079ad8cd8652d70a94aed1d6802bcfe9858f7c8a07964f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d730118081d1c248d74a0737f36e5bd40aa71b512c6be6f68e3664723849ac47a62fc743c4dc7234694bda1b7701f33d2e81000000006d1b185ba036efcd44a77e05a9aaf69a0c4e40976aec00b04773e528633209660001206d1b185ba036efcd44a77e05a9aaf69a0c4e40976aec00b04773e5286332096620593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c18a93e60c572add22525a10a5554e6f6a4feca49fe00000000002ce4f2b5fb4e1ffc000cf99e000000f3a83d259634fbfc3e3c4ed50cdcab6598fce20bf3a83d259634fbfc3e3c4ed50cdcab6598fce20bc69a0bda7daaae481be8def95e5f347a1d00a4b430b8a2161c64bfdc7d621df51de569911a219f718bad4d6058dcca9bddf6696d43ddc4c1e3cf91640c93f820e5680efac30001c374f016ea61e76aab79b8bb95a1ba0e6e3eee6f01fb8f3001fb05a36d6eb7a108fef471947d245e9189e47284d9a720f95aab0127adb9bc6459557a0000206d6eb7a108fef471947d245e9189e47284d9a720f95aab0127adb9bc6459557a20a159f4eb744960b4d191a95585db3f17384e36e5f1cf8c7ceae4f13a1dc46505016c8a0d99a474b91b9119b0b6bfc4da988491ec0300000000005fd91a87fb49c8fc0004e25101fc0005345d01fc000536ab00fb38720e8317dce4ccfc1174da29f071077dd371387b6ba2b25346e89278b4fae874858a8c09960f6ebb7dea2d0ff4054af20815296dbcb9e0cfe2ba30955368e9fb5cce100a0ce6df64bcf624355222e19032cff0c80cbc75140173c2eb47863b189d2423b64af6544226bb50000000006da069138e905fcf845d2e92979086e2bf89ba25d50e1c59799cbf4d2f2a9d010000206da069138e905fcf845d2e92979086e2bf89ba25d50e1c59799cbf4d2f2a9d012055f820fe0081c55c139ebd9eb6d053aadb85d441a7e8eae8dfde4f4bddb3f1ac00777742af1e086c95ad279e2173e6e04937d9206f000000000036bf0f03fb4e1ffc000656800001fc000bd4aa006c0659d3417e8b51836885241a09ac204e87c55c6c0659d3417e8b51836885241a09ac204e87c55c1ec5c66e9789c655ae068d35088b4073345fe0b0308ea05dfec6d5186476b3096e34f6777c221cf0bbce352daf402bb182e2d94297521ffe8c3d09e3e430376fc5c147fe64000000006e736990d9bd8b9b1c0164b8634a07c0da1a2bce1543e7620513b5c95fe288490000206e736990d9bd8b9b1c0164b8634a07c0da1a2bce1543e7620513b5c95fe2884920db520fffbbe239dbebf8301c7ce3bc55a891e467cb3dafe3479fc4e97072d84700ca6b25bd815213810f685818fa28dfb0760b07c8000000000036b856cdfb4e1ffc000bb3b40001fc000bcb8b00a0efde49999335db44bcaeac0af934a4759ad34aa0efde49999335db44bcaeac0af934a4759ad34a1ec5c66e9789c655ae068d35088b4073345fe0b0308c74753516550b53c30a89f5d0c5e08cdc0145d1be5e45d8db75597745346ff4aacc04c1de1f31aa42e43e3fba15ec6b000000006e84dcf6f2ddcf4444bec6dc070d9cbc52c3ef6681a14238b2e1390a77a6435e0000206e84dcf6f2ddcf4444bec6dc070d9cbc52c3ef6681a14238b2e1390a77a6435e202208e9b3635f0fcc623f88c9f45256d6557744d5aa12f126adc3d07ed43a2e8d0192ad947d47ae5f960ea418954db0f96dda7572d60000000000175b61d3fb4e1ffc00025be10001fc00025c4400aff050dc4d29cd0413c1890c6d8db9e8372b4cd38d83de554dcaf4e9c01608497bf4b6bc63210142a4687a0e78a9b3a071ad6ce8e33b008ab5cb7dca300064583f3f5dbb756708aa405572d2eaf3349ec2d9048c93f21a2d1e5a0da7ae1675d27d626035ce0754de1898d5cc30000000006ebfbf45a7e6f5e4d25ba315f1e1a44178f6961271b23925a2871d0c5b9e132e0000206ebfbf45a7e6f5e4d25ba315f1e1a44178f6961271b23925a2871d0c5b9e132e20a06518e3c9374e778a185bf5a4d056b1816719feb626112da42d4a065fdf5e90000b22ca74c045f776efd482aca95f692d3551dd6500000000002d3dbaf5fb4e1ffc000c6da10001fc000c6deb0035d5591040d1158f08d837b59f0b57b6912560cd75246a92185e0f116ef70707a58be008da5ce1680b22ca74c045f776efd482aca95f692d3551dd65300f57b0dd5947df31adba9480eda73a2282aeee0bace77680da718af1b91a05f878e433e8455ad56a38918b5aa262be09000000006fbe7935a362d6c08e5d10af09398ac4ebd2edcd1f5d657816c4f0982da6999b0000206fbe7935a362d6c08e5d10af09398ac4ebd2edcd1f5d657816c4f0982da6999b2051352f9cdd2b3bed963c98435f57a9c2c868773e4aa0ac4e3b8d07afd2da0b3a004b1eda1e91bd4d5907b65f8755c4e3e0e12453d70000000000a5e3146ffb4e1ffbc4110001fc00019d0400fa2440f3ed05121bcc2463ed00d1664946b68b120f4dbff3f157e6fbdf65169a1c1a26fedf178dfdb2334b22379811352d9988876a6e586d975e7329300dc936ac5a2e0e0e81a682afbf1d5a4b6c761d265c944b7065cde7c0009b103b6e163441eab78460b0aa6951477123a0000000006fc2e949a1bb5bff22ac494c3434d2db20a61bc91c9f8a3e57048292abd33f780000206fc2e949a1bb5bff22ac494c3434d2db20a61bc91c9f8a3e57048292abd33f7820c73a0b3cce7ca6c5b5370ac2311140cdc30315ddb718f8c46bc2149894da68d80194970c5f6511cf4757972c8c723ca5e097d0999f0000000000c2100205fb07cefc00040bcd01fc000468e101fc00046af300e565047bbe00199e47400db3a356034373647fe7c8a4cfec45b3e5793f8413968d3bd6aa7c6bfffd9a5ff3a72145e4bae41ff7842782f8e851d4275b30032bfab78f78c968f4a1e7fb87d9b3bd75dd2a49e18b7592e4274322660c27f213b898442eb41f5db42291a2172508b600000000712c0edad9b39de087a2422aae59cbee77b63aef06de6db44b2b8287303620ef000020712c0edad9b39de087a2422aae59cbee77b63aef06de6db44b2b8287303620ef2078d4881f8591d4de1be992256cb869064f8a1778c71815e1854c8258f505a3fe01087514e6edcdb460ec2ec30cd6479db40659f0900000000000c9100205fb07cefc00046a5f0001fc0004709400b0c562adbfdb889b2e9cc84e0858209799bbe16857ac5622d91ea4b76a62b0e4d0a47bfc4a1fc03c9d2a53910bb9aaf740ddcea71e896e5fc5aa5239300ec57774146e447ac6cf131a40fb37664ed5f9ff45b59d22cc68f2aa9f4659cef42235b63c3f2c3ed36f8b2344399d2f000000007135069642e1a72807a383fb5a14b9af6758292fee53fe2a7f7ac6f528bf70190001207135069642e1a72807a383fb5a14b9af6758292fee53fe2a7f7ac6f528bf701920593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c1063c03764190123b001e65fd3aa12c030df5bde82000000000036bda427fb4e1ffc000cf99e000000b920a2229f777e360b7da76885a556bb439533bfb920a2229f777e360b7da76885a556bb439533bfc69a0bda7daaae481be8def95e5f347a1d00a4b4309472710b11e34dd5f6fa0d43cdde23ddb33558be1539cc7275cf06ba2d82c6ba0c712e7022752843f411e6702eaa736d0001f9956e70daffa263e8cf29fa6557b7b630a595a801fb8f3001fb05a3714874684cfabe0cca907ff0e61bde28c2fc1a8840c485fa14ba5660bfad5e2c000020714874684cfabe0cca907ff0e61bde28c2fc1a8840c485fa14ba5660bfad5e2c201bbc52c48482f1e6f57e1eab3d8dc53904d5a16f9bbdabee5724578a8bf897560194cbdd7f7e53872cc579e60314867dcdeccea50f0000000000b6327d55fb4e1ffc000218db0001fc0002192400efeb6789243fa23cbf6b5137aa5d4dea847830e33f309e73b02fc83f88a0bf28f87d715a48678ea6e3c8d9b74f3cacd7ab94430574b9816e5047b9033011b8a3cdbf872f868b08b211878ef11a0f6f7a7ebd55533864aa98e53e194faa159ae2d13a7625384a3fd1572f68deb4000000007161d8618826c76aad36d8b59bc4c1fabb1d8299115f8314e74d7854fc3ef6660000207161d8618826c76aad36d8b59bc4c1fabb1d8299115f8314e74d7854fc3ef666202ae863fa61ba16e37e3dad6fc5c07939b8caf322da44272eeea7f645c447234b0049ec22c09c3152674ae7af85ee7e747d08ec387900000000010000000000000000000000000000000000fc0004bea80001fc0004c8e5019676669d0daf4a6ac06239eae91b43b4469cecb49676669d0daf4a6ac06239eae91b43b4469cecb449ec22c09c3152674ae7af85ee7e747d08ec38793000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000717a502e11bfa52d11a10635536205d60934f6f2d0ac64d7fc0f1808a5aaff01000020717a502e11bfa52d11a10635536205d60934f6f2d0ac64d7fc0f1808a5aaff012014d197a4d96ac8c0895b28bfa5ba04c094fdb7a9e073407a499b07b391d3cb980147a99e2ca7487d874d547e887d3f457175ae5897000000000040b032a7fb4e1ffc000d08f40001fc000d091300b7fc053090e0f10f64d962b36ef797ae608f4851b6e879f9bd59a349caa9d490f0bd51988bb1fc341f9162e004553e9fa0d415cfc38431bddd799a6230a90fce30ea814b244dc767b5d29bf227842226705a0bd2e8589e776a4dd113ed3dada52c6a07f55be90173d6431d8f340000000071d1eee72379edada11d464bcee475b37371e4d907db5848c3f50e0bed00a45600002071d1eee72379edada11d464bcee475b37371e4d907db5848c3f50e0bed00a45620e86078d3a9106a2cf3762064b7326edfcf99ac4e1dd76d6e80c9b94bd766737b01c34bf769f46fcc5ba593c2f3a4009c02e6e0cac000000000010000000000000000000000000000000000fc0002d5880001fc0002d5f10159b1ebf04d63af3ef87391a0a4a7b47f5f5e791159b1ebf04d63af3ef87391a0a4a7b47f5f5e7911c34bf769f46fcc5ba593c2f3a4009c02e6e0cac0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000071e6b3fc43cbb7a04eac2799d8f98f76f3b0ac867a8b8c82caf876cd0737ac9800002071e6b3fc43cbb7a04eac2799d8f98f76f3b0ac867a8b8c82caf876cd0737ac98208e8e515f7025352e7c608479e413beacf0d95cbb964b47e4a98fd27b6b6b628a51ce81fb48d349c7ac0e09a8a5d152475b586f4275000000000034d41347fb65f1fc0005e6990001fc0006579c000883903918c1154fb2b589d80caed855a157b1240883903918c1154fb2b589d80caed855a157b124ce81fb48d349c7ac0e09a8a5d152475b586f427530975c482384c7bd4cfd5930fabac11646121d420e31883673dfb6e6e3bfa273da73a2a91b4b69cc108eff9619fdbb4cf4000000007228951470758be7eecda8126c7a23fe8ad019e67f3fdd5507003bf0d2d4159d0000207228951470758be7eecda8126c7a23fe8ad019e67f3fdd5507003bf0d2d4159d209d15d4d2f03b000755dd3f7fe619d08afe237a6c12a8cdeee78b75701495287201e0e440d4c365236c93f5fbe402336cba2c5a506242c80000003feee5bafb270efbeb250001fbec0200ad045f8cfda05187e5dd3f59cdc7f7692816320a5fb5dd519d994f5e5706b4047d65ba1b873d9ffc818d7b316758b285e41c565599c9168da68592913088d719278eef605d9c19037366910b59bc28d437de4a8db4d76fda6d6985dbdf10404fb9bb5cd0e8c22f4a914a6c55660000000072ee70fa75262781a17d1eb69a6c3e97328208be98b59d5530164f31e481d3aa00002072ee70fa75262781a17d1eb69a6c3e97328208be98b59d5530164f31e481d3aa20a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e60d38405d40979e4834a09345b8c7398e0ef14293b0000000000235bd038fb4e1ffc000ccadd000000889e8cd2ab0cc70e36e566648e265c7536a8fcaf889e8cd2ab0cc70e36e566648e265c7536a8fcaf64f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d73091f9052f62561db112ddca7df3d914d546866b130124eccb2ae1e8419563e51f239b2efec3d1b3fd388072610939d6940000000073091b5bc227073da93ca7c25ffee4f9c9e8b3f77b935c99e30e71268704f5ff00002073091b5bc227073da93ca7c25ffee4f9c9e8b3f77b935c99e30e71268704f5ff204cf1e357dc63a5335aa184c8ff929e4db36e83072425065c0655e09f072fea560000899ddc10954edc1ea1398edfd31b0621e5982d00000000008d47264efb4e1ffc000b3c090001fc000b3c630094ced88d9bd5cd2ec75faf451a5e3bb46f5eca6f90614a6e4cf57a7381bd81839ebce238cca8f9f1349317eb79cf1748fda1de3ea69a777d4272c2ee300fa3db9b808db89b49f91f6136cfb966288a56d731c9afd44dc8c4819ae5c286d08dc0572249f41dc919f888d562340100000000731ddb4dace693a27ac91c696685bf3e01440e2f5d57b53e2ed57059f6a33e0d000020731ddb4dace693a27ac91c696685bf3e01440e2f5d57b53e2ed57059f6a33e0d200064d134104e9a09e6e469e442e305ee542d1b5136a7dece41a2b812e3d89a2a00a4ee8867262e7b96728c873c15ae6d983a9e2478000000000036bfed34fb4e1ffc0006567a0001fc000bd98300cf3908c18dbc7d817330d948866a29f69ca15a75cf3908c18dbc7d817330d948866a29f69ca15a751ec5c66e9789c655ae068d35088b4073345fe0b0301213e8a0f73b54c388c26dcf85c158dad87ce9889f45a38bc330d1da4d73a6c02a8d9f6cdf60cdeeadf084c2749fa47d00000000737cba5a656579e1d2becfee2d92f6c7ae3b84a8ecef02c6f53764a6499a8c79000020737cba5a656579e1d2becfee2d92f6c7ae3b84a8ecef02c6f53764a6499a8c7920931fa180adaccb45deeea0a6a7dd618beea65f600ac6fe734e871f97e4476691004b1a70c1e0e8bfe39a5879c943a850f21875508f000000000012ecc7e8fb4e1ffc0006567a0001fc000bd983000eb5e37e0ff88007604e4ebdb28c3beb8120d5fb0eb5e37e0ff88007604e4ebdb28c3beb8120d5fb1ec5c66e9789c655ae068d35088b4073345fe0b03017de44da9886d130629436db995acc9d5f0ef849ff32c4f57b65674f19420dfe8e583dd2c5f37f88edee1ca119f0e8be00000000753f4ae544d5a43787502bda92bf3f635143a0953b31a62c2f61cf8c7df4345c000020753f4ae544d5a43787502bda92bf3f635143a0953b31a62c2f61cf8c7df4345c20141a04d46e28743a8ab8367ab44f05114161e45f3799c2b9f822d8f9895365ac001309f03f9235a96efbe29a9ca62e8fc600208c3c000000000022de04c5fb4e1ffc000bb3b40001fc000bcbaa008186bacf6b22c42e8a63e48c2b2e1ac614bf92db8186bacf6b22c42e8a63e48c2b2e1ac614bf92db1ec5c66e9789c655ae068d35088b4073345fe0b030147039e55cada215fe076a972b046224b43198c9f8d4ddd55db4dc38e4168ec1bcae3cad84f0bb2d9f3db9688561c84000000000754b89dae8db20fc4cee5e3adb07b146d7efe508a66fa0a8e1094675b9daa35e000120754b89dae8db20fc4cee5e3adb07b146d7efe508a66fa0a8e1094675b9daa35e20593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c19ad66f3780f47e83479e1846ecca44d71ba5a902f00000000002ce92c5ffb4e1ffc000cf99e000000e65f1647a5477a20d178b12c509738d7a35ff312e65f1647a5477a20d178b12c509738d7a35ff312c69a0bda7daaae481be8def95e5f347a1d00a4b43099b9f0fbeea3822cdc5b3654dea52103b3d9d5f01db4201955ea3689074d37da4711d8f313d4b5458eef3395aa75bfc7000146d938862af6d9a291e26c0048177db2892a710b01fb8f3001fb05a37551fe264f2ccc4e714195d2ffb79eea7ebd47517a7164c69653569b10f51fc30000207551fe264f2ccc4e714195d2ffb79eea7ebd47517a7164c69653569b10f51fc320c14b73c62e6c0b2df561e37a65ab15e2813a4fbbaa182eae0bb87e3506d4bd9b01b96ce21a90ba65c455609913a18eb7ff20ad55c70000000000a1bd4319fb4e1ffc000376690001fc00038a9c00abf73c421d3d73583ebcd9fdf55fe8b3013a8223abf73c421d3d73583ebcd9fdf55fe8b3013a8223fa34940e957a62dc7177dcf44e74e39828a2a371300becd48c0d44ca6fbff3825f55c35a6f70024f2b8f4f939260d40b5b51c11cdfff85f7d0444a1a9cb8fc45bacd237b310000000075adf981e3a77630507882a9a41d551ee1e5b8ed570e61a855008ca293e615ad00002075adf981e3a77630507882a9a41d551ee1e5b8ed570e61a855008ca293e615ad207a80d77b707fba35384adf0c231ce60d32273de39c9afa9ffc3edf9a2605fa7101828af5d4e701d9c3869a22f2417110f518f364fb0000000000a7636e3bfb4e1ffb9f600001fbeeea0082242bff3c046e018b795b7bc3bb8667628dc02b82242bff3c046e018b795b7bc3bb8667628dc02b69abc168964f63618f587649cb25ddecfb20fcca300fd87b62bf91162008451c1f00a1d7bd65ef581e88c153d105970ab30e451378966b6e4141e68024b3976461605e84020000000075aec7fff319c066890515c7d626166cdd3a28c9bbcd5d949027e5aec46dcbad00002075aec7fff319c066890515c7d626166cdd3a28c9bbcd5d949027e5aec46dcbad20a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e3f7100e7a52bc4a9c2bf5ba1bed4da45153e0f52de0000000000235ad9d0fb4e1ffc000ccadd00000036e3ce4c7f353ef721fc1754406cf534bab728b036e3ce4c7f353ef721fc1754406cf534bab728b064f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d730124aaa5688cb7220be4600211257ae054554583ad9233e8ca0d58abafe317129dcca9e34a1b9bbfa175b88d9fb31b55e0000000075e5c254c195ef04d5bd91294b78211263726c3bc0bf5d4f92690144f65660b600002075e5c254c195ef04d5bd91294b78211263726c3bc0bf5d4f92690144f65660b620052fc2a04f75b150e4ab7c5981bd24532a49805ee42167b6058b832e3b0c2b5300a9b4fc06befaf833456c54d913154f8f115b412b000000000023573001fb4e1ffc000bb3b40001fc000bc7cb00cf3023e2146c3765ae4218f86e605ac503019d63cf3023e2146c3765ae4218f86e605ac503019d631ec5c66e9789c655ae068d35088b4073345fe0b0300100ed63b1fc72b11ffaac5471ec57d9c9a79214f936932e6a59ebef5938be6190ec7de6b98cf6ae92964d2c7a03cb0d0000000075f082ddd488b36e46fcfe4c5284898d3139ea58f9effa9b70fa12b25619890b00002075f082ddd488b36e46fcfe4c5284898d3139ea58f9effa9b70fa12b25619890b20070280de80a8c5f34f7eb94dc35d847530f7ef5a9a6d43d840b2256829e297aa00c4fca50e9f87d5a53b57d8a678b4fc048c7e475000000000010000000000000000000000000000000000fc000ff1b40001fc000ff220013baaeba63dfa6ee2fd67021647213b024f30d9593baaeba63dfa6ee2fd67021647213b024f30d959c4fca50e9f87d5a53b57d8a678b4fc048c7e4750300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000076476a2678d5c1e9ea4951cdd00babd50f6c53f91427ba8dc8fe49f5dc1f5c9700002076476a2678d5c1e9ea4951cdd00babd50f6c53f91427ba8dc8fe49f5dc1f5c9720ebd8732e4738756b96dee3c0e3e60a0027e3b31c3fb0804ef78d46182a84e81c01e03b915271e6dfe5b91126e4bc7b8a981c7459fd000000000034dc3d58fb4e1ffb34f501fb355701fb81fa006dddbc8e0c2bf0803d236fcba6cc32a8123ef43e6dddbc8e0c2bf0803d236fcba6cc32a8123ef43e49d0dcb6162703c2544068536b0b1813c459dff83010142d44041c90621d111283fe46fd8b2450d4b9bebad194290fce09ba080679c748b1ba70e3959623f127af0d2bc9c400000000766c3edf3c134fc0b5ede4fb57b15564819caad310b1929cb5b57251114d64e5000020766c3edf3c134fc0b5ede4fb57b15564819caad310b1929cb5b57251114d64e520b07dc210a205645699a1c7d92d55b55dddedc6fb6c9a7265d1588320a024736501f09070f51717b8bc2800781c21d9b10733d912ec00000000010000000000000000000000000000000000fc0001904201fc0001904301fc00021efd0096b5ec297ab7b977f1f3318291a77ffad070259d8fce46d5cc1aec576dbf5ba0ada049a2c2c64fb3655d3f8b0d7ac259ce9244933bb35544a1341a7d30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007718edad371e46d20fad30086e4acf4a05c2b660df6ae5f2a684aebdf1be42900001207718edad371e46d20fad30086e4acf4a05c2b660df6ae5f2a684aebdf1be429020593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c1feea83c4756a349e76b9077636dd04b3306bac60d00000000002ce3894dfb4e1ffc000cf99e000000c0e3581e5165c63790a2b8d2670fb4a1917cd4b8c0e3581e5165c63790a2b8d2670fb4a1917cd4b8c69a0bda7daaae481be8def95e5f347a1d00a4b430b675a1940be872b6a0d4e1696bb39ea38179933a1bae02ae1eaf4b47f625bd939482f8791eb38925af47f73be027a64c00010498ade3c80045c2a7520e921180ae1c39da5c5701fb8f3001fb05a3777dffee76d4ac2b3c9222e6d3ce285527a16281b1d22d511fdfedde4e46ee70000020777dffee76d4ac2b3c9222e6d3ce285527a16281b1d22d511fdfedde4e46ee702079a698f19126f940710af2e89919bf10587c5e9de50451d2f53e76f05ece62a60032b089976a177c7b080b8bdc40d5f387113ed2c8000000000022d73700fb4e1ffc0006567a0001fc000bdc0b000f39e252e534cfd876389ce5770a92ab1d3454ab0f39e252e534cfd876389ce5770a92ab1d3454ab1ec5c66e9789c655ae068d35088b4073345fe0b03089fb9bc6b79eb7b71f8b0dd60c2eb5e0298124b9b10ee29c85415f245c67f4a3d7a8b57573e36110c85fbfedea7129110000000077fcca4a0e43f6e0b96687a87b4272eb8523315c8f2a176d0a2df549a869f3af00002077fcca4a0e43f6e0b96687a87b4272eb8523315c8f2a176d0a2df549a869f3af20460c7a309c739da005bea72bfbf0e74767da84a28f8524f8f5b328518ef147cd0177947714219c0af2be7af73357d3b65ffb6513c800000000008b9fce4cfb4e1ffb5df50001fb97a200f2d2bd8ce0dcf0434c3cf661c2045c6fdd22ba57f2d2bd8ce0dcf0434c3cf661c2045c6fdd22ba5795e13b9a85676df4a1c90dfe0be9725ed714828d30914aa95d1c7d7c39e0a3b213b6497f5c8624d4f476b8043b22c4f30cd05bc037c80d02b42625d743c6a18d0562aeb579000000007838259f0ed6819c5325b663499299319c7e882353c922a11c8ad517a0df99a70000207838259f0ed6819c5325b663499299319c7e882353c922a11c8ad517a0df99a720f3f696aaa2fcab176b1032150d96afaf982b58e24faa35b0c842ede6c9953d6300acb39ddb2ca2a929b3fcf215b699fd2459072ca4000000000022dbd200fb4e1ffc000bb3b40001fc000bce430070a68f83c21da5efaf550eaf261357e8fbbbe4b370a68f83c21da5efaf550eaf261357e8fbbbe4b31ec5c66e9789c655ae068d35088b4073345fe0b030854c69a40b8e3d4209fa88590a9119fb6274d3270618bbb0bee5bd22c801185369babdaf658d5bc6946f55d3e5e14f60000000007893b72d36e71a7b83a1fff61e4fbbe1400b11f12bfb349923397a2df3a9ff4f0000207893b72d36e71a7b83a1fff61e4fbbe1400b11f12bfb349923397a2df3a9ff4f2008ea185caab7f5f289c78dee4563bad2e103b12f662fd23eae770e5a04c48c44016922eb5a8a9b1d41b93076ad1e0a908fc6c5bc01000000000036ecd608fb4e1ffc0003842f0001fc000607bc0069d9f48f92fcc82ac6b04a2b303fb420c500f78643497f4ae216cc6f837b4d82ca8e6cd348b636b1f32bb66d6fdcd07b1268d21a3e021c9c954452933092427cdb8c9694e0c6ba086ed7c00dd9f52ca18e335f65de8a839a378b1e040b279c05e3822e7c2fbd57fa8852d04cf40000000079d1d6276e486ab033dd0984a1da33470b6ef293e19492f459cfba43e703f5f300002079d1d6276e486ab033dd0984a1da33470b6ef293e19492f459cfba43e703f5f320a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e55b4c00cc8352c3dc490b5fd1554666a1c90240a840000000000235d97bcfb4e1ffc000ccadd000000e7378cfcf68e9645d0d0ecbabbeaeb48af9a5ddbe7378cfcf68e9645d0d0ecbabbeaeb48af9a5ddb64f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d73092cafe1870e043973b2f1fded8de3d5a66dac5ade46aa0995157077efee92d852857bc7f03ed69c92723a58f8bd2926e000000007a1ae04de7582262d9dea3f4d72bc24a474c6f71988066b74a41f17be55526520001207a1ae04de7582262d9dea3f4d72bc24a474c6f71988066b74a41f17be555265220593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c1cc1d71953a4a45bd11d458683bbf2ef794d6d6e3d000000000023a612a6fb4e1ffc000cf99e0001fc0010f2fb0063c8d3ed082eb5d476a0940ef9c3fadafc4c5d2c63c8d3ed082eb5d476a0940ef9c3fadafc4c5d2cc69a0bda7daaae481be8def95e5f347a1d00a4b43093943908436a934c08582583b08cbcc50b4478bb79b7718789c25eb0ad2f3e5713ad4c152d4b1fd13cfd12bf896072e600017478cfd163788e3bbe09645776cf59642f28e37901fb8f3001fb05a37abe11022a30fb9e614725880e035fb48a8438d3885a3762cc53b2c3cffa38240000207abe11022a30fb9e614725880e035fb48a8438d3885a3762cc53b2c3cffa3824200c66ca577eb357cbbf6b8e64aabf19a07ac6876fb673547b44f6fe65a0e1adc10143af4ad2582f518ac45af4604ebb893c30a198ee0000000000128891a5fb4e1efc00012b310001fc00012d8b0028895ba824b3989b308b4062cb93c22a842e885ad6f5f660f9cf13ff1ff56a13042be5cdb214c1c114da731fe63359a29148e3f59d4235d5bd261c53308edd5cbdd7b381c92ac7de638440bb1ad417af0e82fece69432f36930a6defd3faa0d53d79bc3347ef684eb1e470abbc000000007ace7f64afc3f78ba5dcabc7f384a1a01ebd4d147f8ef629a968df09885db2770000207ace7f64afc3f78ba5dcabc7f384a1a01ebd4d147f8ef629a968df09885db27720a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e0a122072fe97d1a974045569ff2ed7743096099716000000000036d4597ffb4e1ffc000ccadd000000139d5a4134c30bebba6a178a1c8cf91d8bc47b33139d5a4134c30bebba6a178a1c8cf91d8bc47b3364f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d730826fc7f30c49215b98d5cb47a350f888a306c52fa42c77e765b55288e622f03859273cae7e1cac99e67f7a9a96a6aa2c000000007ad29bc543761bfa9ee6a8be1f32bf5bbbc4f979d036676835b4717f8abb92110000207ad29bc543761bfa9ee6a8be1f32bf5bbbc4f979d036676835b4717f8abb92112039a506efedb5d184475201e06dec512e3216b1e42b1d7c0d6f8b0440e6e6f69601c51cb65f93928d010a18197b6c8631c41edf55cd00000000010000000000000000000000000000000000fc0002d5820001fc0002d5f301224cc410b74ac6206018520cac60988122bb337a224cc410b74ac6206018520cac60988122bb337ac51cb65f93928d010a18197b6c8631c41edf55cd30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007bf37a9b228fa18b95fe74186ebfd2f16a15b970fb0ce68c43fe7dd3ca1924470000207bf37a9b228fa18b95fe74186ebfd2f16a15b970fb0ce68c43fe7dd3ca19244720472419cad37dfe438ce60cfb70b9156af1d2bf6e1874fe958ba18f229b7af37b0133c019d4b8dcd9ba7a78607bf0a8f3c86bba886e000000000009080706fb4e1ffc000763f60001fc0007641b00e6dd610e8d417424f55f90b5c468011307051ecae6dd610e8d417424f55f90b5c468011307051eca02216766b853b1e605f1e7ffb5f50c61278ef9ca30897af9fdc7920426089efaabbae8aacd61ea4306c0a2c89b140c9d3a69a56084dabcea352d2e1ff8e1f3ae127313e989000000007c124a4c83e1947d0474b005dd388928970147153d2d6ac4a5d3ac7a56a88dd90000207c124a4c83e1947d0474b005dd388928970147153d2d6ac4a5d3ac7a56a88dd9208ed933b32509d96770e36575cb341bfadd20d512271caae9816fc65e0c4d50da0081c33ea64d832d50287c2769407fbab4e9487941000000000036f46ccafb4e1ffc000bb3b40001fc000bce2b008e4a45ffd92c0a560ae047a37ae10ae6082acac98e4a45ffd92c0a560ae047a37ae10ae6082acac91ec5c66e9789c655ae068d35088b4073345fe0b0300cf64b243bc58bb385cb911efa5aa0675e9a05d582e9a9aa9bec875931bd11e82c652a7523e37c945be068f3a5af5002000000007cbb7c6b65f9360c3ef908ccf93ef438a449938acf05c743b7b92647ab3ad2640000207cbb7c6b65f9360c3ef908ccf93ef438a449938acf05c743b7b92647ab3ad26420534d653b186b8ab60b401e8572d1f8da42eb274441c955f65c59f0fe3d275158018da8375dd317a277a3f946077e1c970a1d8ccdc8000000000068f85c62fb4e1ffbca950001fbe5d200f46b2001f6dd71cf0fa69aea9f5a71ff61423024f46b2001f6dd71cf0fa69aea9f5a71ff61423024709834244eb07040d585e826f04d8d26b016555130136de56a265eb21c006bd312a0353c7c3eed46f4f63c301c348fb5d5de8f965c9b60ac6a4ae805d0d241e4942821ed9a000000007cc4df7db9cf413c897452820cd2625afffc89711f0a26eefa7cb08f8806a1720000207cc4df7db9cf413c897452820cd2625afffc89711f0a26eefa7cb08f8806a17220f6b63b050d5a90a14e3d59047050495646ec5e1242ba53b62ce81cdafbeef24900e2a84d616dc589856872cf05535d435c81f4cd190000000000235b1690fb4e1ffc000bb3b40001fc000bce2b00cec1c86cf65d548313f4401d83ac2ecd67b89a35cec1c86cf65d548313f4401d83ac2ecd67b89a351ec5c66e9789c655ae068d35088b4073345fe0b03009c21792725c0c58038362caec9e4c73f02fbdbf2244404d91b39b3788360139178a60e16e9094af50c71df853c5d2c1000000007e065c97170d9ca4aff3f9815a989c45a81bd7cb2d691fb32b3282ef6e9ccf8a0000207e065c97170d9ca4aff3f9815a989c45a81bd7cb2d691fb32b3282ef6e9ccf8a200c7bc19d6b2acdb1f6f33f065a8c4e1522af8f036e65cae356be2ddaed7f1b9e004062160cb5c4f52f266ba4c0318d365450c9137100000000003695f949fb4e1ffc000bb3b40001fc000bcbaa00817a4306a27d64e71528a625310b5f347d55d180817a4306a27d64e71528a625310b5f347d55d1801ec5c66e9789c655ae068d35088b4073345fe0b03099b0d7b98000098120aab913482266dde9ce62412767f2771bb4b51036a59f3f93d65ab54b583641dd565e47132abac0000000007e1d6bdfbe135910f32160c96a38469c52e0c8c3af6c489dfbbca6b187e978490000207e1d6bdfbe135910f32160c96a38469c52e0c8c3af6c489dfbbca6b187e97849207c4283aaa1bcca10b1358405b9a9758b2dc48b90cc7847af63fe78f08e96f262016740b901d43493fde55958720fbe004747d1c7cc00000000002d4db010fb4e1ffc000374860001fc0003795b002226272b80f5aa9fce78cc60704f1dbcf81715012226272b80f5aa9fce78cc60704f1dbcf8171501b624b6528c6d0ffdd4993a76a23d06016cdefd73300d5a850d41302b179b9009a4969537c5cbf7f0145c94de4306a4e09115ec00248cb1aa76cf04249e2a5104b5cfa86879000000007e56cc8c37501f3db794a554deb4287ac61c83635a0dec6d0f8e0b54ab14f8cd0001207e56cc8c37501f3db794a554deb4287ac61c83635a0dec6d0f8e0b54ab14f8cd2095f18528a48b7308195ec8201220efaafecfbf4df55cc2c8ab6b518733c22d63010e3edcfe65ca42dccfb1cb826562a46097c6f044412000000022df662bfb4e1ffc001066880001fc00108203006afebaad117b22669d50cf8bffc7863662b1d7e16afebaad117b22669d50cf8bffc7863662b1d7e16c671d1b8ae658d8102e47f0bb3f795482a6e215308156eebd6b52f4146a5b3f9686b9712f48980dfa4e8f17b514ba185a31e8d5fa7568c69aa79d9533fa6efd380c27b0c00001390fef6518c3b4b95551fe1707e0f0c398d5580801fb682001fb01bb7f3eea026e3a3bbc8552525a653de7ad02256e664dc6a0dd5e85b6a4aa5386da0000207f3eea026e3a3bbc8552525a653de7ad02256e664dc6a0dd5e85b6a4aa5386da204dea6406996a98efea88a66bddbe7f9568093185b08c865b1b664ae0e594c7be08b1dce6de276ab51d6d1e36be38a3bb1908438b0d000000000036c96174fb4e1ffc000cf6350001fc000d08b30013b0b76a88de761e2de68dd590fb9b636aa288f613b0b76a88de761e2de68dd590fb9b636aa288f6c69a0bda7daaae481be8def95e5f347a1d00a4b43094916711f20db42a7a62118260a70fedcf09443a263ef1891a0744601315b81b03b68fceff6a505581dedcb794a164cd000000007f771a55bf8d18d1ec8c60e61494546e5b9ea1d0639369aa5d09cb3ec7d531440000207f771a55bf8d18d1ec8c60e61494546e5b9ea1d0639369aa5d09cb3ec7d5314420a56ba768ccfa43f27b401cc24a58c43bc067da2b413ea55538d03d322de2e75c01e5ca81c3110acfa3ac727a1bd05453d6cf06bceb41200000002f4b449afb4e1ffc0001c4110001fc0001c61400ba437071f332909dad28d293eadd2d532700e8a1f0a5dd8f973cec456a2423da87b5f1aa97f282e02f8c9d8ff7ef2ad45047238e6bc187d8c124247f30842b8e5b5cc0841de193f440d5fa3e0b4a34df7fffa798fb8c3df46fa31187162cc3b3ecf929689ae35e04cbac6e069f00000000802811a147502b6982e3b863c43b6cbe305cec9929ef3bef5674122ce17cf1dc000020802811a147502b6982e3b863c43b6cbe305cec9929ef3bef5674122ce17cf1dc208c47b1a602d9a9b72807b5c193807b04179fea1d2bbbe6ba2ea6fe36e6c5896e001a135a0120585004a87405b40ed844252aaf6bab000000000012edd9b2fb4e1ffc000bb3b40001fc000bc7b30000f9c0ee13e710b556c5abb7dba04252cff9525600f9c0ee13e710b556c5abb7dba04252cff952561ec5c66e9789c655ae068d35088b4073345fe0b0300b53e680359dcb0decea5bbbdc65576c6a03efc22d93347f19e635feb55fe0cdff6c0b9685dbc999d889f8eed8833fdb00000000807b6948d2bf213b63f7fb1af6175692b6df4629a6c83d59d933ca0c744a0007000020807b6948d2bf213b63f7fb1af6175692b6df4629a6c83d59d933ca0c744a00072007004a740cca33d9593dc8a62946dfb6925617f61afbf7633b21bfd248697b80007dd6b299910d521be585a9288ca0c7b20c9ca26f00000000002ce28ea0fb4e1ffc000b94c70001fc000b9cf300b5d77242ba975cfd47ebb7c1c6f991a868622f1867d64f06bd6c80af5a0ce510c05488c6b605f5b27dd6b299910d521be585a9288ca0c7b20c9ca26f3091ecae225a25f252b7acb8e79173ab1eebd850c6415019b7ba8d11510a48591c2d4d863ba8b716fe38f248fbe8a1f06a0000000083977cb9a12a31f510641cf6bf09190ebe245b167d9b455cd0437a197933dfcf00002083977cb9a12a31f510641cf6bf09190ebe245b167d9b455cd0437a197933dfcf2073839439e285bc285f129f2439f8f1d6f01092909bd405c318e10b1d68d5af2501eb95c9099b7ea9dcf7d12eab52c964628d99901500000000003695bb4efb4e1ffc000b9bb30001fc000bd21b00c4cb4d2d29e56d01ad22d35a7e9cb0b1bb694ca5c4cb4d2d29e56d01ad22d35a7e9cb0b1bb694ca51ec5c66e9789c655ae068d35088b4073345fe0b03091aa06ab2cf470a4265fbde61c153eabe3bd5efca205dc5de54c42f0041b163cee67b72f3b1da2962a5dee3096cfb580000000008458fbd557903692f8e27b4639421db21b0f90469d310bc9221ef592519cb3250000208458fbd557903692f8e27b4639421db21b0f90469d310bc9221ef592519cb32520a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e66e4dc94aa0f3fc1bca598bcc432424bc69ddf4de6000000000036b87e19fb4e1ffc000ccadd0001fc0010e78b00158c9bc3beedd2fae2f1a25b954f315c4fa44f6e158c9bc3beedd2fae2f1a25b954f315c4fa44f6e64f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d7300935576848f6ab7e27fff34b671953672012352e36f5147181926b8bbc9e8b43b98458704666df25d36f37d41eb7c6940000000084bb939170f4714be54d6217cffa5a3818a1c521115d45141b4df642b1dbc5ac00002084bb939170f4714be54d6217cffa5a3818a1c521115d45141b4df642b1dbc5ac20fc2b411dcc940c02c50ba66566ebc630687c29da1c8c6797c24a101118202d2801b4b492aad7a4e1697be9c6c24f6b4ae07b46190300000000006d61d62bfb4e1ffb8be60001fb8c3200dd52f6e013f0cff9cda0dae34d43317bcb66edfadd52f6e013f0cff9cda0dae34d43317bcb66edfa976b7ff055f5ce7ed9315f6bba901f6064495822300f4002936319c495d9557ac1bd514bc760cb8db72dd99d5d20af93dd5a7570974d75e5761fc494de28127ae02413819c0000000084cb17f8193558315fbb5acb6b285f80c3727489f3f167380189c73751ee99ec00002084cb17f8193558315fbb5acb6b285f80c3727489f3f167380189c73751ee99ec2049c551c2b1b3c0a0e8c90be10c5847f49f7573ba6038dfe56dde66127bada0b3001b35584083c3b6032acef150d939f606bdfcbfeb00000000010000000000000000000000000000000000fc0004bea80001fc0004c8e50197726f02d3aa3114065784a38c5b0c7dd66811d897726f02d3aa3114065784a38c5b0c7dd66811d81b35584083c3b6032acef150d939f606bdfcbfeb300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000084d181ca2e1afd3fb416c71f62c2f5370a1e7f54c3400faadde30563e62f731800002084d181ca2e1afd3fb416c71f62c2f5370a1e7f54c3400faadde30563e62f7318204d00207605a792d8f6a528dadf5169b89982dbe9614f11224f70c4b03d45cb4301f3ce2464a6f42e28bdd570214f656bc226992fc200000000008e5d284ffb4e1ffc0001aa950001fc0001abbc00a4e27301bbacc1c42b5e2268bc2b4400599edcf1a4e27301bbacc1c42b5e2268bc2b4400599edcf1f3ce2464a6f42e28bdd570214f656bc226992fc23005b69b964d581a7659f5fcf2cf4a50a75e9cacccebc4e18d27364225eb3f9886de5472cfffbf9cf029f81b49037e27a20000000085412e8586e7e2015db1d2e9b4dd380e89251ed812e40bf8d5e220ee40bc18a000002085412e8586e7e2015db1d2e9b4dd380e89251ed812e40bf8d5e220ee40bc18a020da0c7a3d5af8a813d69d33357370066a2f5e1f7aa6fd6672090f355b81c3d566014c70d3eeab48b3455b85cfd354c9b4de7c267e3e3c23d70a00a747dfd4fb4e1efc00024da90001fc00025d63000835d0e8b7da48d8880e8d3420b7c8351c7a31d84b682e8847992b8e9a2531cef5a3169ea5b80c58d458f5157d91f4832e66eb8630ab3dbff95551d83080b7defb6341399f9e9b4ed7c2d627fc828d0eff9c168165b75b24e5fc6c3f5bc8a9eeaee2bc655fdaa58c0d2f3b1b940000000085f15a31d3838293a9c1d72a1a0fa21e66110ce20878bd4c1024c4ae1d5be82400012085f15a31d3838293a9c1d72a1a0fa21e66110ce20878bd4c1024c4ae1d5be82420593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c1aba3f43f7376b9025296fa73a30c07ccf5266eed8000000000036c92083fb4e1ffc000cf99e0000000f89b9ac5ac8f31255f692a3eb0283d0ef3be4360f89b9ac5ac8f31255f692a3eb0283d0ef3be436c69a0bda7daaae481be8def95e5f347a1d00a4b430ac3026b3e3023db1db9ec8e3b7678761820a2a6e96e7a5d9a39b1894170f9cea7765d3d131d60fa9d17492ba560fb1f9000168c506d43816d1a8389c860c1d162be44d1e777c01fb8f3001fb05a38627ed5599adf01d97427316b0589c2e97ba6418916a9bde5b2585e1c9c4f6250000208627ed5599adf01d97427316b0589c2e97ba6418916a9bde5b2585e1c9c4f62520aafe6abef33b368787d302dc54f71cd0a619d4f988d3263aecc745238871bd0d01deaeccbae07a6664dc82067b7cfff4ff84c09c1b000000000022d0d181fb4e1ffc000bb3b40001fc000bd203008b582cf224fbd769b14e7bab26bdb4e0c9ca5f038b582cf224fbd769b14e7bab26bdb4e0c9ca5f031ec5c66e9789c655ae068d35088b4073345fe0b0301261d7939ba80738dd1ca4ed73829488159433938e37256803daebcd7042f1963a66a2eb58622a87cc91aee8225a464e00000000869b6700423da629920dc2101ec88e894f450f66aa751879dce0468945e04179000020869b6700423da629920dc2101ec88e894f450f66aa751879dce0468945e04179200c0397f81c000328a2de9d047105f8e01d0ef36fd900ad13691aeec8c536595501352b6ca5a0485762fbe87165aaeed5c05ed4882700000000010000000000000000000000000000000000fc000192350001fc00021efd00e049e560af6d16e85a90ec84285dabca4e44514e011b1a772ead943d16af20c36c7255e18ea51027c0f5b027f3497c6e3151b44b63e43776d34c3b62300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086b8061fb7fe866b492b84e85aa0548f68ff376c4cbc5893e46ae361a5e5724100002086b8061fb7fe866b492b84e85aa0548f68ff376c4cbc5893e46ae361a5e572412085accdf9c5e5c660057521c0001e313efd673a38d30be926546f897d5b71fdd901e0d22538c2de001eb6fc6c2444c442e944e888e500000000006deb4738fb4e1ffb1c3401fc000132f901fc000378e300c8270f9d208c75006659cedd927f04ccf829242cc8270f9d208c75006659cedd927f04ccf829242c39ec59af37fd69ca39664fea97c3a5d3758f3b17308d1412ff39045ef39c2e19a75cb3ad986afc14c3139ed0a3392b41d471558676029a8137f95b0ba0e7315bf11c497f0f0000000087075234ac47353b42bb97ce46330cb67cd4648c01f0b2393d7e729b0d67891800012087075234ac47353b42bb97ce46330cb67cd4648c01f0b2393d7e729b0d67891820593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c071594bae6e759f13fbc246c11fbd8d97d68911241000000000023a79195fb4e1ffc000cf99e000000762e689e7bfecbe16bfd0e6138eea642ee0513c5762e689e7bfecbe16bfd0e6138eea642ee0513c5c69a0bda7daaae481be8def95e5f347a1d00a4b430a7afe7674de986aff5e2e0a173be8c29abed8b5d6f878389ea18be0d43c62ad1ba66a59e9e8d8453aa0ed1a69697675800019b9cdbfe3568cc0b37f136b00a634c75653f05e301fb8f3001fb05a3870c6a346d863f0963e4a5f251dcd712b0a8bd8ef6aa8f63c7ccfdf981810705000020870c6a346d863f0963e4a5f251dcd712b0a8bd8ef6aa8f63c7ccfdf98181070520634482f1393532816bd77ece32a84a17a334ac110e47184574d16d8b772261c9007d4af03527d7d34738eefa6bef126718c5e4edc50000000000235667d3fb4e1ffc000bb3b40001fc000bc783006d8404dcefe34e6d52bdb4350026dc8ce574b05e6d8404dcefe34e6d52bdb4350026dc8ce574b05e1ec5c66e9789c655ae068d35088b4073345fe0b03001715f72f5b165d307bac41c2f933aff79265d1b3b7fbcea31e1cf842ff4955b8ec9f510391659eb05282aaf7434b4b500000000874c44b97f12d2ab126377cacdeab45e3fff8c78267c71b1ad051a714d58e6d5000020874c44b97f12d2ab126377cacdeab45e3fff8c78267c71b1ad051a714d58e6d520a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e4da1130bbd7061d88f984d3ec1507026ba9b2493b3000000000023552198fb4e1ffc000ccadd00000001ecf043431973b9cff69b82f15ac7f6a6eb15cd01ecf043431973b9cff69b82f15ac7f6a6eb15cd64f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d73015a577f51dc6fd7fa4621f0a4601e48fd65418a89c2af2afef725fb4f053a8ee5841cd3fdae39ebdf5a202e0c4deca230000000087c23375674218932c768502d4ed00794fa327b0a95f3fd07e3366021284a8ff00002087c23375674218932c768502d4ed00794fa327b0a95f3fd07e3366021284a8ff20e7b95bea480d82316911dec49a09e8ab6a65a40fd4fdd93f11372737636de4cb019dd617c523be40d62d6fe6c8099a2731bb8f64b200000000000353f0dcfb07cefc0001d4d40001fc0001d7830041abf15cda4f87c47836fa95b0e6909449272a4af2b29900381739339a74d57fdbc677a6ef249f1c040683a4f0f1c3abb09335c41cba814d8f1a24a3308074793934715bde7630f4f267a9647955ac45400792369bd3e5f88e2b9d6c809251b79428e3a8ec07bdbb7364e3c2990000000087c5a82f46522a809f60943985bdbbe6ab131f49bc4b35602c0b2ed34dab354d00002087c5a82f46522a809f60943985bdbbe6ab131f49bc4b35602c0b2ed34dab354d20ae0e04e42fd5e99597eeca25834c5eacb8c990957a179f2873cf4b913b97af9d019723404c2622b84de329f7bc2459cc224eec9ba03c23d70a009de62866fb4e1dfc00025ea30001fc0002847c008a8dfe8a388fbef15d0035c320ebefd5ac5ae2463305078857e34417e861260119603fc23c67d221d458f5157d91f4832e66eb8630ab3dbff95551d83084fb8f4119d367a2336982fecdcf326c56b7c09c0911994720ebe2a657d5d95252be1871889b13f81cdd16d49e15a7d30000000087d21608895b8148fdb2c846d5401158720c3721dc07c4fa0981f2bb25ae52d600002087d21608895b8148fdb2c846d5401158720c3721dc07c4fa0981f2bb25ae52d6201e4a5c4121ca8d8f8e51946d9fc42b510937cc7e0a0b9ff1b353aa316ce8a4fc017433ee61219aace0ffab939271e77c28e1290556000000000044b7a536fb2714fb6a490001fb6aa200419483f32fe1e48e4fb5ae37cb31cd39247ed46a419483f32fe1e48e4fb5ae37cb31cd39247ed46a6428ac0c44a1383f70c2fe1f13b588e2dd3b14dc30974b7b4e608007f22ece8fb933fc18d66cf35cc0e5a7977279a092976b501786d4ab9108c7fda681e23978bf54b7709a00000000880ddeceb54dfaa8c4750e03f69d38c06dcb2f8ffa9dafe9b3f7a08d28d45e99000020880ddeceb54dfaa8c4750e03f69d38c06dcb2f8ffa9dafe9b3f7a08d28d45e9920a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e63dbebe4f6a661367d4a83b8f988b5759628d7f66f000000000022dc5551fb4e1ffc000ccadd000000a9cab48330c4f2058fc7d331b9355b91056c68e1a9cab48330c4f2058fc7d331b9355b91056c68e164f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d730111a30e0a5f2f5135dcc5f09498e4ba5de22c7680f396599f7f29b91ac569c3d4336bc157443cf8c06682bfb5abb22710000000088251bd4b124efeb87537deabeec54f6c8f575f4df81f10cf5e8eea073092b6f00012088251bd4b124efeb87537deabeec54f6c8f575f4df81f10cf5e8eea073092b6f20593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c03090aa69c8d1a95839e017d1b2b53d3499fa0a9aa000000000034211c2ffb4e1ffc000cf99e0000000799f054652c1cef10d2994fb83d012d559a1faf0799f054652c1cef10d2994fb83d012d559a1fafc69a0bda7daaae481be8def95e5f347a1d00a4b430af9cd8567923fea3f6e6bbf5e1b3a76bf772f6a3c72b41be15c257af50533b32cc3923cebdeda9fce7a6bc9659123d530001711fd9548ae19b2e91c7a9b4067000467ccdd2b501fb8f3001fb05a3886622da5d1f1b025f69e4cd924fc1928ea35d8312b807d8b50d63107fbd9a16000020886622da5d1f1b025f69e4cd924fc1928ea35d8312b807d8b50d63107fbd9a1620afdc274a214d9cffbd84cca49182cdd43ad3abf0aadb1546dc88cfe6c0a754ac0008dcd60f55257d858dca51e0ab3b65e4680cf572000000000022de0637fb4e1ffc0006567a0001fc000bdbf3000fa716254623b29b7651b989fbada389aafe097a0fa716254623b29b7651b989fbada389aafe097a1ec5c66e9789c655ae068d35088b4073345fe0b030162563fec3d0cae18031294dd0f6a4bbcd153bc1c087b18a7438a95650a2225926347ed3f7cb4723972ad97251b6b35d000000008917bb546318f3410d1a7901c7b846a73446311b5164b45a03f0e613f208f2340001208917bb546318f3410d1a7901c7b846a73446311b5164b45a03f0e613f208f23420593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c21fe8d862d5042691749e866af337e50e599e64fdc0000000000340d8492fb4e1ffc000cf99e00000018d9316618b1f55977af250cc5d8783617084aac18d9316618b1f55977af250cc5d8783617084aacc69a0bda7daaae481be8def95e5f347a1d00a4b43087d25769002af2a4f050127c73fff03a24935e48f34fecaacd69410787d0e6384b345c78e81b1cb397b43dcd635568b600015bdbf34a0dad860c6ec71523ae39373325225cc101fb8f3001fb05a3892048b276a248b44e0e0c498fe0133e19a9a19ff03d2a6201779759a9e597fc000020892048b276a248b44e0e0c498fe0133e19a9a19ff03d2a6201779759a9e597fc205b016215386c035a42042a93736befccdb87c30cb90adc3b1279da58ac57cc14035a6f7ff4fd5aeedd90b2d4a9a746d07039afe6e3000000000022dbcd67fb4e1ffc000cf8b101fc000cf99801fc000d04c300db6568bf9cb89a725c973fffccd4baf12b4bcb82db6568bf9cb89a725c973fffccd4baf12b4bcb82c69a0bda7daaae481be8def95e5f347a1d00a4b430a7676e9a8ef4eaafcf47451801388500aaa1c1994c5df1619eb3b54b83dfab28c7969b262454c0397fe6fc14dc8c62d9000000008ab9b419adde6c292a0376f1b010293252bbb70b7d1ac3e08a843cf7c1d1ec390000208ab9b419adde6c292a0376f1b010293252bbb70b7d1ac3e08a843cf7c1d1ec3920b7ced6bdbb2bd4be7c03c89225aa80a21fa0f189164195d6b38e852a9f615a66000abaa849176e61dab40c075e5a1e80e0f5dc8133000000000022d18d8cfb4e1ffc000bb3b40001fc000bcbaa00a3b6ec8347384c53813aa4eec3f5b4608434ad71a3b6ec8347384c53813aa4eec3f5b4608434ad711ec5c66e9789c655ae068d35088b4073345fe0b0309226928f9d21053e24678f1aea92d7668e8c8b6f75c07519a32a40491428908dd31fcc8c7c630d92eb1255592169b8ab000000008ad0ad3c5d5e607a7978ba3f026240beb079a186a784e2034b41fffe917c46fd0000208ad0ad3c5d5e607a7978ba3f026240beb079a186a784e2034b41fffe917c46fd20a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e458fbc9d5e0fa407cd7238155ef388b400bdb7aeba0000000000235cdb7cfb4e1ffc000ccadd0001fc0010e77400cfbd1e90f25b6978cc09db70685726fd4469de39cfbd1e90f25b6978cc09db70685726fd4469de3964f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d7308ea71272ac9a9c891f0987a75e2200a44fc063bca92892c0a174cff4c0a524935e0b870bd091329836e43ca7d7c87e7f000000008b8d1193afd22e538ce0c9fb50fee155d0f6176ca68e65da684c5dce2d1e08150001208b8d1193afd22e538ce0c9fb50fee155d0f6176ca68e65da684c5dce2d1e081520593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c0b3fe432c394e3e96e8804a8e059b1887afc913012000000000034229032fb4e1ffc000cf99e000000b802f02882ed36279ba95674e7e190e86bd6458db802f02882ed36279ba95674e7e190e86bd6458dc69a0bda7daaae481be8def95e5f347a1d00a4b430a1749fecb407bb0e0ab9d6df65ea068dba5dc03e14dcb36abe5cb2b5c6e424683f715ff09ce290d035dbb31add0c01800001a0a0e17bfe82a484fefe348b7569a6d77d29d2c201fb8f3001fb05a38b971ef085c168cae87c3ef20dcdebb23a9a26eb7d47a4f793aa2353bed4018e0000208b971ef085c168cae87c3ef20dcdebb23a9a26eb7d47a4f793aa2353bed4018e20506cc8538b9cda4631382a1226a65d86a77ee7ca6fdf7d649c06a104c956903b00e91bdc77d4faecb8481e9d54c7e69a74c98d664c000000000023a63971fb4e1ffc000656800001fc000bd4aa000466dd0bf8e08e82a49b9d1e42872510886ab7630466dd0bf8e08e82a49b9d1e42872510886ab7631ec5c66e9789c655ae068d35088b4073345fe0b0300d82df2de7cad8263357f244c3c20824b450e7ad24c6ab0e264a0936b7f737e9402144c5205d4e38507dc90226ab97f6000000008ba8c6867b46bb40408022696bab30719990806d6e5eeebebe8e5377228b3ac70000208ba8c6867b46bb40408022696bab30719990806d6e5eeebebe8e5377228b3ac720dc964f0dba071a3102960a4848d57042e6397a041568e0d8f988d79202fcab780186f37c9afcf2222c2e1846e6aca7cc3075cbbf81000000000022d2f6b9fb4e1ffb7a1501fb868501fc000119c3007dc8a7ab041ff32acaee3dcfcac1e36bbc126cd2b2ea896299dd86bc7c3353a40d354be43ca263727eb0a0af302dd9ff95daf9e98d2f1f2c5d764f74308b5d53516c0c7134efabc77f5f7d19b6e289b5e8befc35ca5d77626a252e659888fdd09a7c9bb286dd9fc4d73025bcd7000000008bcd5c2b4956f890f454d07300fbc2bd5ec291f9f68c5ab4f44af8073a5fbd8b0000208bcd5c2b4956f890f454d07300fbc2bd5ec291f9f68c5ab4f44af8073a5fbd8b20a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e59c3439bb3f8a5f9106af32c1c8cc8d730bbbd8e9e00000000003646f303fb4e1ffc000ccadd0001fc0010e84b00365a8a65e5270895c8e0a3557b1bb425c8efd7da365a8a65e5270895c8e0a3557b1bb425c8efd7da64f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d730183e7c881c6c556701b21eb3f837e2661ad4ae1ad5b9f11faf6cb1246daf99157f3da6491b8dca8517b33b32abce82a3000000008bf18698fd403d18f976fc5f89d79db263fb354a63781a512e2d48faa17190f10000208bf18698fd403d18f976fc5f89d79db263fb354a63781a512e2d48faa17190f12051d89c906e2bddf572717e4806a4be5db96b544b5c9425a069351a0e218c9c2d01e973eded63a3abfb7f48eb28c27469e5da76a01e000000000017f0e8c3fb4e1ffc0001ca240001fc0001ca940039f55c68417e332cb9d56879392d0d34b8858df704dbf4531a1c3aa937a63bb4d5a67f13a335d5c3b1605918c84d18613d2c487619ae380f36282ec8308041404bfd1cd4b71416116af92b7a17f42c47bf3dbc2294369fe1691eccb9ba851183a0e85a4fd728c946a582d006a7000000008c15296dda100476466c2af9f2d212097c0dad634c47894e34e89b0772a7ef6a0000208c15296dda100476466c2af9f2d212097c0dad634c47894e34e89b0772a7ef6a202dd418858077835bf0cee0935325099557a492a8de9117e9477c520eb8349d5c013db931950d15afac53606bc3191ea0ceb8f1a0380000000000340ce25efb4e1ffc000b9bb30001fc000bd24b00bda32a6923c976abd03cf593ee3eca92f44213e0bda32a6923c976abd03cf593ee3eca92f44213e01ec5c66e9789c655ae068d35088b4073345fe0b030858aa595f574ea2a3c76a01d3de5ae733932304d08be169583c75df7879dff27232b0aae832aaa25f318c38794b9f670000000008c754a2bdd2ace903ed98aae9f52f481e7a6949ccf422f4297e0ba9a500ca2740000208c754a2bdd2ace903ed98aae9f52f481e7a6949ccf422f4297e0ba9a500ca27420a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e51a502e87250d362827c252cbf2a4b54bc793b34670000000000340c3659fb4e1ffc000ccadd0000004bbca9fd6c162000d1042f510196c4d069bb05f94bbca9fd6c162000d1042f510196c4d069bb05f964f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d73014eabcb82f2b0b9cda8eaa3cecd39f0058b418cb7a25795f597a811895bfcc23643bb25ae8432a52804dfb53575b649e000000008d4d1bfc7e6667a370e072079dc70b3e3268f71a32a54371487339429aa475360000208d4d1bfc7e6667a370e072079dc70b3e3268f71a32a54371487339429aa4753620431d3dbca48a3392be9c41a68961f2d1cf3d5e5b93151b2b1e47f635e03ba2b6001d70b39a95401ae5dd407a846e9a775a92513f5941700000002d3f6868fb4e1ffb544c0001fb669a00752afd96dceb969687676e32c4cd3116b76a5c84571ac9b0061529d85a340440e6fd38a3ad5633c847b71db162f3f607a3fde13909f0df2e296a72703005e588704a6f6d703617081d8328c006b1173d60aa26cfe44b954f1279a1ba9a042bddc5b3a00cbc8180676d12060d620155ecbd72e31176702506fd6219751a8ae1a6c4310000008de8b12952f7058d827bd04cdff1c2175d87bbf89f28b52452a637bc979addc40001208de8b12952f7058d827bd04cdff1c2175d87bbf89f28b52452a637bc979addc420593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c1dd08fdbbe79813bc43a306740d2182674141d76de0000000000342b56e7fb4e1ffc000cf99e000000300904176cc6023370b2462964c12c5979b9f411300904176cc6023370b2462964c12c5979b9f411c69a0bda7daaae481be8def95e5f347a1d00a4b4309502bb884b3437d65c0e025e49fb00ff6ea9f55d5bcdc36330b46c8bd18be9126b7a6d7f35f558ef8040f2c2284500a50001337b7fb5d2c531825c3e0123ac3354018085b30201fb8f3001fb05a38e0c95f8f71cd450abe7495077ecb431068da7821ca4e38af735565ec630deeb0000208e0c95f8f71cd450abe7495077ecb431068da7821ca4e38af735565ec630deeb20a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e375f7056751bb5796fd2d228ed85f5c88b053e6443000000000036be8308fb4e1ffc000ccadd000000d28ef7142aa96b23b44a0e7a5294dc2152e5f53fd28ef7142aa96b23b44a0e7a5294dc2152e5f53f64f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d73094a0bd3671bf20ef2a75c2e1723eda50a4d7566ceb0f5e018af7c576e11b1320b4b370e703afd4a7220a7c5688414040000000008e11eb784883d3dc9d0d74a74633f067dc61c408dfdee49b8f93bb161f2916c00001208e11eb784883d3dc9d0d74a74633f067dc61c408dfdee49b8f93bb161f2916c020593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c20f53e3ff160dab7ec3cc2a6b0afa6dd8d36e38794000000000034599a30fb4e1ffc000cf99e0000000063eb51fcfd121e6c3eae23b90b26cd1100217b0063eb51fcfd121e6c3eae23b90b26cd1100217bc69a0bda7daaae481be8def95e5f347a1d00a4b4308160877a911d8bb7d1e75e2320e98cc3233c1f6972cb642424bfcec7c182c56d2c0ebb59e45f788f4d5dbfa2ebff3e3a00016d57707c196e06487d326094c964f258f5b77c3501fb8f3001fb05a38e7a3cbb99a9ce89685175ce3b3b5efe33498f22ddb539a2c66190390ff9e37e0000208e7a3cbb99a9ce89685175ce3b3b5efe33498f22ddb539a2c66190390ff9e37e20a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e325baf1be4d6ff7516aa41a0c9947396f5dba016a70000000000235a2a40fb4e1ffc000ccadd00000072ed00fe080bf542275abf350c2922a8a2ff119672ed00fe080bf542275abf350c2922a8a2ff119664f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d730082cbd9118474316f40b800e43f94a121928f256fd340098ff0ad81a902c4326dda4b42737d52739482f2baa80c487cc000000008eca4bcbb3a124ab283afd42dad3bdb2077b3809659788a0f1daffce5b9f001f0001208eca4bcbb3a124ab283afd42dad3bdb2077b3809659788a0f1daffce5b9f001f20593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c0e55b79902ab8dc5c126e61ebd5bdc2ec98d80836600000000003644ebc9fb4e1ffc000cf99e000000983259ad7ed51267fb83a8e41bbaa5ab55c632e1983259ad7ed51267fb83a8e41bbaa5ab55c632e1c69a0bda7daaae481be8def95e5f347a1d00a4b430b942e2e50c5cf9d9fe81119cc5379057c05fe15134f85847356b5d1f6a21f29f4a53f61f03338d056edc15a8c63fbbe80001c075993a8336f93a13bb7bbb7e0e89928be4aafb01fb8f3001fb05a3900618389dd73377e2b33b021d2e8b0e7c51f8f5c1d871af15886e3cd6e6d6ae000020900618389dd73377e2b33b021d2e8b0e7c51f8f5c1d871af15886e3cd6e6d6ae20a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e3a699566abcaa3fe7f3568b95e28dec3bb11537726000000000022dcc2fdfb4e1ffc000ccadd000000e7b23e56a97aec080890987ca187cc902a4efe21e7b23e56a97aec080890987ca187cc902a4efe2164f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d7300dc75e865b89e96560b38fae96f1d0a5438795778e68b705a506046245ca5dbbedb09e2379eea4c9bde0d0fd4fe0508000000000902c18f9e7451f382b6a41e96b766ac3754e792a31e75c8ca0f2da5bda93c708000020902c18f9e7451f382b6a41e96b766ac3754e792a31e75c8ca0f2da5bda93c708203ad39dbb8bfdfb4a46d3f8b1e5b328c4724acac30b82034349a6b831070b8dbe0008cfb189e4df6f2fee5f9c756a0cd23b3c871067000000000053e97783fb4e1ffc000aa0540001fc000ad2eb00747d38fd242d8f1114f47fa24a233831b5305962747d840bce00916fa12947def52684f03a37618b08cfb189e4df6f2fee5f9c756a0cd23b3c87106730198e877839e3a29d8e1e0f0f8db6d9e533902dac30db36ab1330fc4e1e45427b658fac866dd8bb65b0c68b263ebc695f00000000904132db5c8718123233252283268bd908f1585a7a8db92f997c03694914f0d7000020904132db5c8718123233252283268bd908f1585a7a8db92f997c03694914f0d7208e8e515f7025352e7c608479e413beacf0d95cbb964b47e4a98fd27b6b6b628a20484569a0b078f0dcb21a0253aff10ec06b1aaf01000000000034d41347fb65e1fc0005e6990001fc00065754006efa257a906f0adf9b184b0738a187a5b775df686efa257a906f0adf9b184b0738a187a5b775df68484569a0b078f0dcb21a0253aff10ec06b1aaf0130962c65927aa1616e3783ae7cdf8c3d19b4c26b477686a9f146cd9ae40eb7c0e01a1580d5df8c32d1f4c43a52f62ff5e00000000091bbce94c34ebde0d099c0a2cb7635c0c31425ebabcec644f4f1a0854bfa605d00012091bbce94c34ebde0d099c0a2cb7635c0c31425ebabcec644f4f1a0854bfa605d20593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c1eea45a388d248dcd7433c8c8113d5d0966069413500000000003428db29fb4e1ffc000cf99e000000cf83406065cb65ce74100f3c35a0324bfc92dcb0cf83406065cb65ce74100f3c35a0324bfc92dcb0c69a0bda7daaae481be8def95e5f347a1d00a4b43081ad0f9be5a88ae62ff54fe938dfceea71be03bd4c6a7aebf75896e8d495d310acc4146aa4820bc0e5f5b06579dedea5000102aa69f8ef6666e7cad6d9323755a0ef3c1b6bd901fb8f3001fb05a39212f5312730c7881b882b9fb7864dc686fa5a585b7a93253ccf1ce87ee593310000209212f5312730c7881b882b9fb7864dc686fa5a585b7a93253ccf1ce87ee59331203193e57ee81ccf3c25937a5b585afa86c64d86b79f2b881b88c7302731f5129201eaf63db1bbed2ccc65ff8763bf9cabf44b8d6dce00000000006418ef40fb4e1ffc00017eae0001fc0001eef4009f804e8f9cea38d4380e1e4600d4e16bd49ac9d695dc83d7059a8aeca9996d6c5436db3f8c9924fff32bb66d6fdcd07b1268d21a3e021c9c95445293301931bdfa94f15b64ed9d09d210db9998dfa068332fee19d8e1ba4872c0acc3efc723e2fd04a64ef2da473caa4471c69e0000000092b5bbdfcd2d46938c23f5d48ac6dbc2fb041172766455fbd8863cf81e8bc9df00002092b5bbdfcd2d46938c23f5d48ac6dbc2fb041172766455fbd8863cf81e8bc9df20bfbd6a521797bda7e2a5219db241c335870a521037815380e7ac2bca5be84948017bfd226583bc3ca0a3547672f9d264fa04a9d9c200000000006a0c494afb4e1ffc0002fbd50001fc000377ac0007ec0bbe822a5aa140229c9a460489563a7b6a77bb9bd2501e88903aa50a1eb8f36a5eb1fd0a29e250299c1357baa7e34f19a5be2a225eb65f5dd9993007cff9e4c50da82722bf41fa5da01ca4bdb238d8d53fef085a56c34a432f6994c79e5bf754898499ec4dbe91eec0d00a0000000092e1ab09f73e703c196eea46780a14e8eefa5b5e1c0ee31be05718056e020af200002092e1ab09f73e703c196eea46780a14e8eefa5b5e1c0ee31be05718056e020af22020904a313c770af35f380bd22f3f7a1891a7f368e4594de5889adb9beae26911003306e27f0719a83ffd6ebd35183d8dd714991b39000000000012ec7145fb4e1ffc000bb3b40001fc000bc7cb004c6cab39e8742edc7d062b3ec2c51aee9342e8dd4c6cab39e8742edc7d062b3ec2c51aee9342e8dd1ec5c66e9789c655ae068d35088b4073345fe0b03011b5a1fc5f84431ab1546dd7189b7ce61eb9a0615a96e4467819a4af04a633627aca3494cf5636f2376228bbf7e91b470000000094044c070f9ce6bdd05c2b655ad2383c8402a74c10e0a9a3099d759b33cb763000002094044c070f9ce6bdd05c2b655ad2383c8402a74c10e0a9a3099d759b33cb76302081dbccc2d89066db311d0d2ca068436e6d98ffce705abfd0ecf69d70f7206ba401b542c265e3f41425380ee61edfec8a5dea7fda0600000000006c3dbd90fb4e1ffc00023acd0001fc000529a4003c7b27ea1137b6aa8714ebf68d9c54fd7fe23b414915c7d1e335096ed8afa549bd4b52c6491d0df912b3c0f5799b64529486fff598dc276c4897154630996f5888a81b9668c16a12c87134536e3616c929a7b67b37aa06d3eb7d7e405e3d3148ce7a072128c9063e1a8042eccd000000009427f6cbb0807d4783d74927eaf1a70e9c19339ac47ac7be1dd80b0ca4ec28350000209427f6cbb0807d4783d74927eaf1a70e9c19339ac47ac7be1dd80b0ca4ec283520a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e438df2a5d0be49659e711d7ee517481e23107fd25e000000000022d1eee4fb4e1ffc000ccadd000000de39cdda2efe7dde604c1965fa539df01785bccade39cdda2efe7dde604c1965fa539df01785bcca64f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d730959f6f2d48d283390b246a55b19a267f8ada326c8eb67f217839d5d1cc55377d8c1a2962cd5e80b892577454390c36b800000000957acb5bb59e253059da86924b5bbd94c1daf5b0fcd313bdb78e43bdc7cad000000120957acb5bb59e253059da86924b5bbd94c1daf5b0fcd313bdb78e43bdc7cad00020176deee4e53c297f44029a7db294451139901bb49f33a2a0ac8bd1b9e744fee201c406356d37513ea70f93868797061aec981337a700000000002d87b4aafb4e1ffc00102b8501fc0010594501fc0010598300cf0ea50da406da09dd78689abaa7c44aad428e3f37f1afe5852c1aece552ed1be61dc898a8db05f06e0e8a6ca912d408dc8369365e947a41d9d0a9d83098fc5928355798aa9237b107935ba606bd749e16f2922d8c4eb6b6c2cbbb4210f3bad09fe7d199aa3884fae3fce0120d0001a5bf8ff04bf1be7f1d98cb952f1b49f8d162d8a301fb682001fb01bb961e7fe42fe63f21e6e21556d2b4cc8c0423c1e176873efed3a14136dcbcf887000020961e7fe42fe63f21e6e21556d2b4cc8c0423c1e176873efed3a14136dcbcf887206fe932a6b6385b29bcd78378e71a727bcff83226945744019035493b24003e5301892f0612c075706dadccef0848d67a8ff5b8446f4120000000a7637017fb4e1ffc000899e301fc0008a30d01fc0009093b00a656c3104b5aa2a042680aef3494b62eb3ac3e7ea656c3104b5aa2a042680aef3494b62eb3ac3e7e52e70333f9bcad1e0b5c60777fbc3a17bf23e1d830804fadcd7b5dade6f9f577fe663cdf86f1483b71e6fd8e7c5cc4b981c0ee086412b16c796ce8fa3f7b6445fbee8666400152e70333f9bcad1e0b5c60777fbc3a17bf23e1d80000009693e443a6820038ad1160ae01311a85b4573965ca4480317611d5b6e048aa2d0000209693e443a6820038ad1160ae01311a85b4573965ca4480317611d5b6e048aa2d20b7b7b143980f65ade8556b431882dcab54ac9387fef544e8581d709e53d19a000052fc8bcf6fea0c7ac216d544308afa9d8920774900000000003695fc92fb4e1ffc0006567a0001fc000bdc0b005e66b53e3569ba6d1dff160ed56d074dc63f96c35e66b53e3569ba6d1dff160ed56d074dc63f96c31ec5c66e9789c655ae068d35088b4073345fe0b0309058f3873b1b4fcde2ee8c817d04626cad7de91c972988a4288d4548d2585074c11f29e270d094a9ed95f8618ab8ed54000000009712e85d660fa2f761f980ef5812c225f33f336f285728803dcd421937d3df540001209712e85d660fa2f761f980ef5812c225f33f336f285728803dcd421937d3df5420593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c1277e135a613d9797db4d7a9d2e51bfe8599d3650200000000002352c5c5fb4e1ffc000cf99e00000020c7f1991e06d09b1f067b049fe6d0af0a20f79c20c7f1991e06d09b1f067b049fe6d0af0a20f79cc69a0bda7daaae481be8def95e5f347a1d00a4b430a8dbccb130522909dc710a65728006732c18441757f12a338cf4a6d8cbd5baf1a484537a6a0542f51bb686e6e546f1a00001ed1131823bcea23ac78af8c01e4d24683d6ecf8801fb8f3001fb05a39767a4cafa9d1057b48de795ea834a15664b58a79d75a4f826299ce1ba11842c0000209767a4cafa9d1057b48de795ea834a15664b58a79d75a4f826299ce1ba11842c20cfc9ca7becc69990bce0fdcf42c6d7ab1317281effbb2bef1deb457d226f3c1c012a566509d67f0566a01c5bc8c19b455095a52eb000000000010000000000000000000000000000000000fc000170b801fc0001b6f301fc0002289400f3fab21f5d1e86919c2e57fb4561244688c773aa25df60b3535787ed34aa614aeeea9f99236ea994f0e4fe2e70afb072ea5c2d06f5cf8503068add46300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000098ef58c338a0a68e4f2f1d1ee9eb05fcafbb9177d192dac0f698d3d9ba09209600012098ef58c338a0a68e4f2f1d1ee9eb05fcafbb9177d192dac0f698d3d9ba09209620593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c178b5541d75eaaa98f8ad22355a122c55741f339f200000000002ce8c406fb4e1ffc000cf99e000000caf6f1b9916245ce300a63fa2254ada25e0423d6caf6f1b9916245ce300a63fa2254ada25e0423d6c69a0bda7daaae481be8def95e5f347a1d00a4b430b6175b59aba8cc0477d4fff78bd90294f31ebd385c39bc254c7995a5dd3ccb8dc1d8869e247bf63bef8ec79317f479a90001d6ece912cbf02627a4efc3dd37e6833cf367155101fb8f3001fb05a3995d7facdd36d2db5a0e3621ea50678ce494149b4d2dece73d4a7fa2e095ac1c000020995d7facdd36d2db5a0e3621ea50678ce494149b4d2dece73d4a7fa2e095ac1c206a963e1d05f10a5a744a8429a7d5ee8f482c4f6e7c4093a2c60c124f4ae2717001683eda694e5f2b0e9edd6f281eaac015f59790500000000000cff66169fb4e1ffc0002055a01fc0002099e01fc00020beb00f05505af7fce03ad669a45ee34ffcdba84636ca2373eabed3a46c91e10415d8a7e0b36c2867b92f96baeb84347272b9450cfad36524806f5f8135952308c26812d38faf159f811a09c1462e07e40d6b44881114358cb5390b65778ee437018c5879fbf935fd78955899b67633e000000009a37c6dc3e32f3c52d3f3af8b4d46b773e01d3bf27817bf609b60631c620b5900000209a37c6dc3e32f3c52d3f3af8b4d46b773e01d3bf27817bf609b60631c620b59020a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e2b481b3ac3d0ca22240b01de36b235aa1eaf0b05a3000000000022d4a1bafb4e1ffc000ccadd000000fd47aa98b58734af1453cdbbe5ef9396716775f8fd47aa98b58734af1453cdbbe5ef9396716775f864f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d7300aeb5c2757211202b3afd2033ec1b4ef2dfe376ba5c6c07b45e6a7460afa4086423c4a704eb9a781514fbc513e190a62000000009a7f3e66905a2588695023cb6638bac294aa7ba4fc332737062398a173447f4e0000209a7f3e66905a2588695023cb6638bac294aa7ba4fc332737062398a173447f4e206c4add138ec5499b898d5d712924cf027be42e67c94174caebf143030cf15bd401d544504a737db17be4b9bcbe091cb419c8dbe3f000000000000de4d231fb4e1ffc00092bc20001fc000b4a5b0092d2b72ce01caa349e82d0490990e20b88bea135fcec2b5f013e92232ebfdc4f814ac10eb533a25ea5aa7b99f9638528d9186dd57d008654a3abc7a8300517910047a316c354423fedf0402dde38c90fb376dfb680e6b2b430addea140d0b6c795d90ca17f1df658a5d401c9da000000009adf02049b965817cf6fb5b675c17dbc00df7e2fbf68cf3377adfe30e3ed0bca0000209adf02049b965817cf6fb5b675c17dbc00df7e2fbf68cf3377adfe30e3ed0bca205e09a967f881113c81812102e3d365e6573b7269ff1613c7110d058e24ea123601800f683c47564b0cf20428c9abbc735e96c6a49941200000004e2eb95efb4e1ffc0005a5ef0001fc0005a6d500a7889dad2c33e1f6b8b68aa5cbb7392d9e96bdeea7889dad2c33e1f6b8b68aa5cbb7392d9e96bdee27aec5b42d8d74dd11d216bd2628111c4d9fccda300df074095e5498c6f1b76508c3ae700484d8b0d5cd12a990f3dd54e35b47d6fc943af4223d390ddaf8989d883c84b284000000009b135e3d6365e6acc8c0eeb513a3c8cfb68525e6d4719645fdb3fb3340caadc90000209b135e3d6365e6acc8c0eeb513a3c8cfb68525e6d4719645fdb3fb3340caadc920c9cf125e893ba997d1e05decc65ca4ae5c3c658df9b693f1c3b8ca6a14c2157800279480b2aaabcef3c8f4d073724dfffdf6696d13000000000012ec1e46fb4e1ffc000af11f0001fc000af13300d89c5ba79b9553a13f783b50673e15283eff3a3bd89c5ba79b9553a13f783b50673e15283eff3a3b49fd7c9727399a9d1d592b68eb09583bfbbe9ca73088ec95047130c4b310db3b6585c2fbe9453c7f5ff43ee5fe844e74c25766488fae8ad62052ec76a6c2b584029e1b1b04000000009bd4945c016d11b08f5c137900df9fd5472726e002fd7531ffdb4b25bb3c9d330000209bd4945c016d11b08f5c137900df9fd5472726e002fd7531ffdb4b25bb3c9d33208a2bba7feee4b42f3f0d1bf6dec1a3360ea7f61d3352af8bf3a37cfa9a2281ad0077398906f47400c2223db65c6d6b6aff09e0dd2c000000000036c83f2afb4e1ffc000bb3b40001fc000bce8b000a641ffc2886d96fc0d6739f2877e0cb81fe075a0a641ffc2886d96fc0d6739f2877e0cb81fe075a1ec5c66e9789c655ae068d35088b4073345fe0b0301964cfb5518ae0d35f2d02dd5c402351c318b79de1c5ee407811fa950b0ea2ca9f794a8d07ce9cc30fb76fb4e9ca3799000000009cb04f271ba050132c00cc5838fb69e77bc55b5689f9d2d850dc528935f8145c0001209cb04f271ba050132c00cc5838fb69e77bc55b5689f9d2d850dc528935f8145c20593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c1bbb948d5d33120f51f2ca02c77a0b69761b719f07000000000022d63044fb4e1ffc000cf99e000000c54ac69739bf492d4328f1bf0d49581ce0b10d41c54ac69739bf492d4328f1bf0d49581ce0b10d417ea623bdf8c5607f0390c85586d83d473fa6a1c630b6ee48c7a71a9d8e0813e68ca09846245fa155285f24a62b0ce9cb0102b1994ec58af8ba2a01c09363bdcc395d41f3df000162e960a3f6b650feed98a266b3ccdf6e363562cf01fb8f3001fb05a39f1e242390cde84d67d9e2caeb1fc042a6bf0c85c8393026733ef5543fb0bd2e0000209f1e242390cde84d67d9e2caeb1fc042a6bf0c85c8393026733ef5543fb0bd2e20428e2f87d85de3d5b6a5a86ea5863d35b08e9c514460cda44dcb7e199bb769350083f05c3c1667334c68c95ededade304e08b756ca0000000000369550c1fb4e1ffc0006567a0001fc000bdc0b00cbc9ac9fd1bebaf88433e4ffbf3199ba365153bacbc9ac9fd1bebaf88433e4ffbf3199ba365153ba1ec5c66e9789c655ae068d35088b4073345fe0b03005987ec3ce6dac84c1b2cbb4753e5f361fd2217ca4251211d4eb0d82ec729b1ca540da4d8649c74b3a82e8a6e4fdafa8000000009f4f9f83ecbcd5739d7f1479ee14b508f2414d044a717acba0960566c4e6091d0000209f4f9f83ecbcd5739d7f1479ee14b508f2414d044a717acba0960566c4e6091d20ae21919b512cc68554ca16c583688865967f5375d107bbfdcfd79da5cccf772a01bfe3d321e667dfd5d7f5922c1d6bafaea45caf4e00000000002d20d39bfb4e1ffb1be20001fc0001850300a2dbf2c2b6149412562f306841959b9cac234b73a2dbf2c2b6149412562f306841959b9cac234b735cadeb631ebd16a92cbe6cac1be92247e95b51463008e37b3fcba972fe0c2c0ea15f8285c8bfb262ad4d8a6741a530154f1abc4edd367a22abd0cb1934647f033913cca58a000000009fcf7b15b9c7ce71c11b7577e05edd1ea922125b9ee8fed7d0d8ff21d530a33b0000209fcf7b15b9c7ce71c11b7577e05edd1ea922125b9ee8fed7d0d8ff21d530a33b20a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e2f5380d6cae296849f7444e27f8ccba243332d0bd8000000000012edaa20fb4e1ffc000ccadd000000f1b18d69579c40dc8292842f02ff5f511e61609df1b18d69579c40dc8292842f02ff5f511e61609d64f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d7300b04bcb5cf6d2d6df5979234611da42854a5e69374a29e0c85128caedb53d9c818042613d2f30f3ef782ed37bd8ce161000000009fe2f8d43c11c61b5a545f451d5f9ffb89bed5bd91f43988eb97ce9a336922810000209fe2f8d43c11c61b5a545f451d5f9ffb89bed5bd91f43988eb97ce9a33692281200e7a78c30d54bc56f44597f4369f988aa213df3bb910776ba9940e048e37bb9f00e06459f7aafb271dfbfd7ed7dd16fe623589a9ef00000000004e2ea116fb4e1ffc0002dcf40001fc0002dd8c007ec334a85c5cf331176646c2c357732ec06eba397ec334a85c5cf331176646c2c357732ec06eba39e06459f7aafb271dfbfd7ed7dd16fe623589a9ef3080174252e0f66a71b7e53f8b32dea5f97a6b39dfc1479c6e355daa415b1ff7733a4bea6bbe3fdf412fed0fb60e5b71d700000000a052764f93c4edb6c4bad2de10f9328738aef20bbcf3185dee993853a746c097000020a052764f93c4edb6c4bad2de10f9328738aef20bbcf3185dee993853a746c097204dea6406996a98efea88a66bddbe7f9568093185b08c865b1b664ae0e594c7be04692f66e4d117895e7a587976901020ee0bb57dd1000000000036bf4419fb4e1ffc000cf6350001fc000d08cb00cfdabb52d6248b141eb688cdb12f8f07641c3e94cfdabb52d6248b141eb688cdb12f8f07641c3e94c69a0bda7daaae481be8def95e5f347a1d00a4b4300f6c077a09de24df2cc17b64543bb12955632f52bb9525df7686f61c5c86d820ef6d71e9e333ecc869e71418cad80cb000000000a07dffc303cc8c8305380d7d1076d4a0b49bf8ea06352751a1480dd40bf806b0000020a07dffc303cc8c8305380d7d1076d4a0b49bf8ea06352751a1480dd40bf806b0205b016215386c035a42042a93736befccdb87c30cb90adc3b1279da58ac57cc1402276e8dda7b00c16f6cb09751662b1ad26766fff0000000000036bc2e26fb4e1ffc000cf8b101fc000cf93401fc000d08b30083abe51882a96d3c10cbe4a277aec4e0cfbe39cc83abe51882a96d3c10cbe4a277aec4e0cfbe39ccc69a0bda7daaae481be8def95e5f347a1d00a4b430818b1f2d7341dbe7d236945a76a2798da654c792e1311a92736ba4de810af25f1b305ce9acb314eafddca5489f1db88800000000a2313686a6daf92c85bf10c45876b257aaa710b6767d60850c78e33905be433b000020a2313686a6daf92c85bf10c45876b257aaa710b6767d60850c78e33905be433b203b43be0539e3780c85607d76b610a7aa57b27658c410bf852cf9daa6863631a20171d7b555e8a999afba6cb76fd165477520839400000000000068ec34d6fb4e1ffc00065b2b0001fc00065b450050b0f07133bb2fecd59710ae0a4baef7223aceba83c1f4c02bce59c4775cec76c6ca37241429c4e2967023bde3c52aa6bca87686da2c8d5f6cbda76e30915b61f2b726d5409a26a41bb3f350c1e4bbeb5e07e808f9f68361d70ac7fc2fc33178ac9639ae7ef484a427d326f24600000000a3b3e4b3d98c934f056a2e76ec8ff07ef8473b87f559295ece2254b3820e54f0000020a3b3e4b3d98c934f056a2e76ec8ff07ef8473b87f559295ece2254b3820e54f02071ec8af2ff6a68c9fe83db26214dc6cfa49f7e48e20099bb676bc08a26e5691801c81d0059d50a9da36b88ec6e8d69cecf84b567d63dcccccd00d25ad25afb4afffc000446080001fc0004713b002ee6bd87c06f15d21562672548ebb844c5877d5bd641c8b61a2c1d3a3bd4e4c850daccffc59a4ef4c5591200b21667500e76c560dde632b87998d67c3081bc001c31c71b0d4d4f9ecfb205e914fd9cdaab4e7dbaf0b320d40f0bd5b193d1be809ca34eb4979d661f487b21124b00000000a3c1bd9b636f0ddfd72bf99f48c516050085973cd2d30dd637a55bf7178af9f5000020a3c1bd9b636f0ddfd72bf99f48c516050085973cd2d30dd637a55bf7178af9f520a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e5ac5bad801f3318192b2d124eae58e0e24cf32b76a000000000022db991efb4e1ffc000ccadd00000080a52baea6d3b53815a8daab24bb7229c3c6288d80a52baea6d3b53815a8daab24bb7229c3c6288d64f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d73094a637afe3810d73e3402b5d6a398e45222ba846a339f1c3570aa8e3f7f5b9d7acef08ac234cce4f706671498330a59900000000a430cff6d81721057000ace8eec27abbb70d223a6bd565126337ed69493e56d0000020a430cff6d81721057000ace8eec27abbb70d223a6bd565126337ed69493e56d02056475cf5f3827ba09e0307be6d1374b9e5fa9e9cc8dccfc96168be082f335031018f67a58864ad617560e1c9e6b181d0305d3b537800000000008a440d6efb4e1ffc000a7e7701fc000a818a01fc000b4a8b00f89615731050212b9a50c9a6039059397601920484a12f2ef1a65969f60c6d2e2b2974c36cb309d0f629010378393c23e3d0e1382099f8c7f3c2157e308e845bfce2651b80e95f37e231301260449d1d89aad58729398208007ee430fc8137c323857bc75cd9bda7334838181300000000a4d877cee62f82868034fb678436d87afbb13330d2b66a24ae1d357f0de55c68000020a4d877cee62f82868034fb678436d87afbb13330d2b66a24ae1d357f0de55c6820fc211290b15b583a7a8b55990bdab4493a1fe73cfd96c238a205a93b9ca23f080160859bf00fe1859bd038ccb54f7def625334914500000000005350e5d5fb4e1ffb35df0001fb51fa00d0669e929f06ac80c05365d9558ad79cbb78f2c0d0669e929f06ac80c05365d9558ad79cbb78f2c068189a3fea9999f9897f4542a7a0170679a3c3713016415af54406658be9ea44d82b6b502bb90d93e32997484533a8a71a4ed98d12cea3709d84a5835b6ad8ed48d310163300000000a565c913052a586db0d5a000007ff981ff3b59982e662e02ac6d45e37bf8f0e6000020a565c913052a586db0d5a000007ff981ff3b59982e662e02ac6d45e37bf8f0e620589799b1d3a737137c9aca1650ad98fe415cc3c035618c9f0f01b60725c2e156014cbf5b172cbd72849fa68c6fab1041a618599868000000000091efeb10fb4e1ffc000153440001fc0002426400d2a33a64d0e54ed860973f6c22ad36aebba1dc9ed2a33a64d0e54ed860973f6c22ad36aebba1dc9e2588a17ab3f917f19afeb8c32fa7c486ab4105a33001e584b5723fec78495744b68b971fd654f16b016d676ffdbac01b2c64f319675eda577f5eaa5cf5379e95418c61ab1000000000a671f057d9937b97c9d256e4eca70318cf51f7259fed49b9ab441f13cc1b12d0000020a671f057d9937b97c9d256e4eca70318cf51f7259fed49b9ab441f13cc1b12d020a8bbae719937bb8bbad2f4067a16377a022dd411f2a676d49815482084d1d235000ba82bccdd17d425113f03d098dbe9a7285cfa01000000000068f8da17fb4e1ffbc4110001fc000194c300bd605f715f78f4639ee2cb9894f6750526c952da61110603fcbf3d2a30482e4901612318b34602cdb2334b22379811352d9988876a6e586d975e732930898839eeb51c078a7785efeed45b73db7e97138eb950b84302f2f13d6b33e6f8e58eb14e52c4a9c168edf50f35d0a4cc00000000a690051e69de6e36eeba664bff34e017f973d27ce91c1f2247120e8ce586b1f1000020a690051e69de6e36eeba664bff34e017f973d27ce91c1f2247120e8ce586b1f120f1b186e58c0e1247221f1ce97cd273f917e034ff4b66baee366ede691e0590a601aba486210cd648afc5ebb8842b543da323eace1341200000002d4da7f7fb4e1ffb509701fc000b9e8901fc000bdf0b009de28ef58bce6c501541a589eadc9900dbecc7dd4d31414b558eff2b3b489b6128ac6852e0fdb85c5a375814e9caf5b8575a8221be246457e5c5c28d308b165f653a3970a17f432f6c3abb8b681c71a3775f998fff322341d2994767c167c8a43b1b4661b9c01ef637763d4d8100000000a776b3114d2137d1eedb0908aecef3c35ef001166bf3644d8c9f149b3843fde3000020a776b3114d2137d1eedb0908aecef3c35ef001166bf3644d8c9f149b3843fde320a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e3967f8bdf103c99ddc20f32961a22dcc88fe23b014000000000022d3acd4fb4e1ffc000ccadd000000127b867e4c2d040cedaff979c39220c717011dab127b867e4c2d040cedaff979c39220c717011dab64f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d73009f8a06bd95c1be3cfdcd2516fabc0858c611d63c76da3a5beaa007b9d7c895aa63c0b2887bd584a76892db417a6683f00000000aab7b2ed5bc2fa962dca591440e22b47ce41bcd2b79394d53dfac5173a3f97bc000020aab7b2ed5bc2fa962dca591440e22b47ce41bcd2b79394d53dfac5173a3f97bc20a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e53b1be8daa1cafd2685237f3e5652da5d0aee9eaec000000000022dcf318fb4e1ffc000ccadd000000853fd590bbfa10868687b7c648238857248adfb7853fd590bbfa10868687b7c648238857248adfb764f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d730018a6d23ae53d6231f7dd73a058f125340e92f6e97897f017d9d9d4e6671bbd92241170dfcdd5a4ab8ef47ef12ddcad500000000aace03a9c75c17bfb8ed760974e5dd8c94f13234cf03a76123b667caf2b71bbb000020aace03a9c75c17bfb8ed760974e5dd8c94f13234cf03a76123b667caf2b71bbb20b78304bdd6f104cf06b25c94e1de8cd1bc493b801983af667840129fa996dccc007e145aa6ecceb9581d21fe84b2c9f536f31ee0af000000000012ec8031fb4e1ffc0006567a0001fc000bd9b4008b8f48a17ec07a3e313369919447fd44560798a18b8f48a17ec07a3e313369919447fd44560798a11ec5c66e9789c655ae068d35088b4073345fe0b03019f3ddb941f0abfa5195a679846217c55a4a9830e73a97d0b93848928378dedb7a416f875525e6f16b2587abda624d4f00000000ab51b2ba4dca27658e13fea81c0764167c1466aa2d92050c67e4490ce7623da0000020ab51b2ba4dca27658e13fea81c0764167c1466aa2d92050c67e4490ce7623da02042b5315bf35d6f493d885fd156c7a9200cdf5e1aa08b27a035bdcd8058f0fb6401c7aca57d5af87880188266cc82fb2e0306d1af200000000000a763a43cfb4e1ffbc40f0001fc0001949300f769eb159cd4004c2546a757e50efced82fa88d7682f324019f53145cfdee3eb63d2dcdc151a5f6ab2334b22379811352d9988876a6e586d975e7329308072ac9a55d1cf5bf9c4262d49e2ef1ffcd716b8983ffdc62b940fec6cb4179d6275f8b68316f29c6c2ad540db32925800000000ab60639a6f7bb2c6c67fa5a65060fa94d3edc1868e8dd16457945f35caee57a9000020ab60639a6f7bb2c6c67fa5a65060fa94d3edc1868e8dd16457945f35caee57a9206a135dfa33b83c7d1afddef6dcfae0a0ff5e6c7cf6cc8f1d07451e251b0d4d8a00766e47227b7aed504a1ef568f67b059d07b67a53000000000012ed802efb4e1ffc000656800001fc000bd4aa007ad999d1a421e1d109569aeb5969d30283e68ce47ad999d1a421e1d109569aeb5969d30283e68ce41ec5c66e9789c655ae068d35088b4073345fe0b030125e7412707146bae96346cdcf3f7ed773646e5547ba57e318078051893e45b0e88ad1a6ae0fcdd89a93bc009e22075a00000000ac5b22cc7947409cd806908ac78a0a600fc6cac2a9a2eeb4a77d8915933696f1000020ac5b22cc7947409cd806908ac78a0a600fc6cac2a9a2eeb4a77d8915933696f120c7ee263d7818e4d18c578e2be6e4858c9631d303131205f9f3a43a6a4df16eeb0020a0d68a349226cc5ff472d2d6ed5cd288856ed5000000000036c81f99fb4e1ffc000bb3b40001fc000bcbaa00abee7c29b0755392bbe29c42ae94823da8025876abee7c29b0755392bbe29c42ae94823da80258761ec5c66e9789c655ae068d35088b4073345fe0b030081d223cb560a023f279a41df68f22478636932932c5e8ea6fbe56b534d4c09603587bbdd2f68a8d6e4f36838030483000000000accd3915d6756cd44d0334a6f753082cd62e723408f02c52ecd7b74280cd3fbd000020accd3915d6756cd44d0334a6f753082cd62e723408f02c52ecd7b74280cd3fbd202b9cfba78ebe0e26d1318e56bdcc2f26a896a166cb7479088558a550ebc86ab400ba7dcabb1a39ea0e8d19419f6b249eadd48352a200000000010000000000000000000000000000000000fc0004bea80001fc0004c8e50154e91ab69c8979d6f2b5f476f666dd09a07f099c54e91ab69c8979d6f2b5f476f666dd09a07f099cba7dcabb1a39ea0e8d19419f6b249eadd48352a23000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000aceff858918e60e1afb3f7418dfac7b05ebe4f5402687a7b31ad0c1f70c615e1000020aceff858918e60e1afb3f7418dfac7b05ebe4f5402687a7b31ad0c1f70c615e12042fa8da0fee62ef58885385a220ba2b8ba2d7a88eadd23137b03c8a3c9c1a92d0025b9f391c4357fd53d01c5e83916a18ad24868be000000000023a36314fb4e1ffc0006567a0001fc000bd9b4002d499b03a1f4cf6ccf3491629430440c885a399d2d499b03a1f4cf6ccf3491629430440c885a399d1ec5c66e9789c655ae068d35088b4073345fe0b0300fb1e1939b4b6e7da5bc51c8ac931736cf02e21b96c8a57e6db35e62c702745d7a838cfb50a87d1acec4a52f6b8a893100000000ad9ae35caf7548cf3df6343dede0e585702eb5cf80306e76b65db2c603baa0ac000020ad9ae35caf7548cf3df6343dede0e585702eb5cf80306e76b65db2c603baa0ac20de3daf0213196f7d5138276d9a81318e2a6f2ff27781089cafc3d3817d8f211800c45bbf7b65fec374b69de7b5585a301558adacda00000000010000000000000000000000000000000000fc0004bea80001fc0004c8e5018a366a03dfaa43d112376f878b171f8df72896008a366a03dfaa43d112376f878b171f8df7289600c45bbf7b65fec374b69de7b5585a301558adacda3000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ae6f0501ba42aa004525f41ffb59ca39f85170e69a241b69cc493118ab745b31000020ae6f0501ba42aa004525f41ffb59ca39f85170e69a241b69cc493118ab745b3120790e6b01db05c42af47508ae009a24e8e0ae633aaaac9afaac23580d0b3e744e002a3b1c1fca3044d3a94b0b264c7ce60e0df75347000000000023a5bb26fb4e1ffc000bb3b40001fc000bc7b3005721268dd22359aae9210eb45596b00ba85de9ca5721268dd22359aae9210eb45596b00ba85de9ca1ec5c66e9789c655ae068d35088b4073345fe0b0308e9a07b8e11d3941637f74c58e60a917e0ae9327bfde9f2b9f1586b52416f4abce50e2c577ff1bdfc0a5d59e094be47b00000000aea2c0ad3c65b374731f81c1c3b9d08ada064798f788cd8346315eab076f6057000020aea2c0ad3c65b374731f81c1c3b9d08ada064798f788cd8346315eab076f6057209bf6470c04b9f1bcbf9c3cb2ff4d5b633101fbb5352f2aded8df1cde62867bea01066c33e3367b1047bdbad8fdcfb3fcd8daa62046000000000074cb570cfb4e1ffc00044c040001fc0004c92c00a17349d2777d28f0cc7d39fda9cace46c23036a0a17349d2777d28f0cc7d39fda9cace46c23036a0066c33e3367b1047bdbad8fdcfb3fcd8daa620463095234e6e7d476318b4811f1daaa7e887fad24b1499b3472a3a7decdd88e8bdd14551b7b67b22ab896adb298600aee96f00000000aedce7a4ed26b9f1975d071c46d6b8792c96e618215b1e3086da5d94543f2ad6000020aedce7a4ed26b9f1975d071c46d6b8792c96e618215b1e3086da5d94543f2ad620a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e0c1b9fe116e4b5263c75a13b5a3b078c30c9a2a6ac000000000012eda5f2fb4e1ffc000ccadd000000996eefc4c3da0c2c59fceec99aac79122c44d632996eefc4c3da0c2c59fceec99aac79122c44d63264f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d730007b1f3f16835ebfba6f505f43c6de757bb22ecf27a89703e90e43aedafea3df353a5bd1915b27e8db397d53f0a23f6000000000aee65248d2955c6954334ada761dd15cb67a58f919e13a41f45d2cb19a35ad26000020aee65248d2955c6954334ada761dd15cb67a58f919e13a41f45d2cb19a35ad262008ac0860ca2a3ddf7ffd7568e37bf192ef8bc83345d12510300fb2cf0150400a015c768ab3ddc84e3d35cb1e9e7daf17a359379a2c000000000036bbef0dfb4e1ffc000bb3b40001fc000bce2b006448d9ce86668d353b6cdef19b1c6523e42f08d46448d9ce86668d353b6cdef19b1c6523e42f08d41ec5c66e9789c655ae068d35088b4073345fe0b03010f6ffb8deec0cbaec7f1284b6cca9c1a46dbb59133c32d58d79490488fce662a9e54d2e9256f394b167ff12b15fb82700000000af33ec874b37177f0ff404564837ad74930b21eca87727b27c2494cf76f580bb000020af33ec874b37177f0ff404564837ad74930b21eca87727b27c2494cf76f580bb20568ac2cbf4c913be67e97440d1666ae9f284a195eaaeb5d6cc088f02c6a40fd8015c6ed0d12929502d6632482c6dc079b38ed1096e000000000034182d1ffb4e1ffc000b9ba201fc000ba67d01fc000bd4aa00c637ae108ab48b62a5c6353f8fdae3578e63e6d3c637ae108ab48b62a5c6353f8fdae3578e63e6d31ec5c66e9789c655ae068d35088b4073345fe0b03018fd8f5cb1579c5a3358126df2a4c0670029ecf97ec95ab2e41e3786bfa9b2c7da308953cb1ea3aebf42910ffbd00f5a00000000af39e406e48c5fac9cd44da1a84541e74f968766bf403718854f8ad2c4f3a1fe000020af39e406e48c5fac9cd44da1a84541e74f968766bf403718854f8ad2c4f3a1fe2035095f3703e5379b03644ff25063c3fc1433144657864d06904b8c4c81235ab8001980cf5e5a4b2e6008ca1f834e297a1a550bb6e7000000000022d111c9fb4e1ffc000bb3b40001fc000bc79c00d3735099e625828d21cd2495e700d8e5fc696bc0d3735099e625828d21cd2495e700d8e5fc696bc01ec5c66e9789c655ae068d35088b4073345fe0b03090680ace6a8f09953a47344b83911d1a1b2c8628d4c712589a9814a04272b70842c9c7cacd1ff5cb19c97e88c67ebec500000000af879b5cbf2bfc94e1a2af602159930146caf7a91e7d9bb08272b82be03137ac000020af879b5cbf2bfc94e1a2af602159930146caf7a91e7d9bb08272b82be03137ac20ac3731e02bb87282b09b7d1ea9f7ca460193592160afa2e194fc2bbf5c9b87af01e31328e1bc246922c2954f8e93562c1e96b9b8ac0000000000ae22e974fb4e1ffc000cf13b0001fc000cf6cb0020c3d21ea834c65e7584f4d3a9270c70297f04d9ce7f101b7f075273c892063b1b8571311737a5767f95c0f808aff27883260bfaf9cfe2b84519a6b230932f6fc90c9dcaacdf9d836a2a7e60d090fe5e55b0b02f5a4f608a4b8235ba5aa7abc4e05f9387d1d942adc57c87f5b700000000b00179bd307619645399361abddcb07287ecd406301fdf405d9a82c8e333aa03000020b00179bd307619645399361abddcb07287ecd406301fdf405d9a82c8e333aa032060c6085ff3174d7f715fe6160822a1ec9a5182e6a6fa7603cdf6759db9726ad90116cb1e8f2ee25a6e24d3bdf0ec74b68635e822410000000000c38d8f31fb4e1ffc00010db90001fc0001854c00307e6b1e1ebb35dc358870ed74feb6563617e40d307e6b1e1ebb35dc358870ed74feb6563617e40dc7bb875d7fd38c672ce10427e7e172735c827f0330878386a8d07cf79e1dc6963d4cdcd7a4af6ef7e350cad3e1373e45fb86fdd9390a77366ccffda6ebe1470c45b0f7591000000000b00c8c773b22a9aa8364340a901a7538459ee38c7a68926e3996be85f6cc0d25000020b00c8c773b22a9aa8364340a901a7538459ee38c7a68926e3996be85f6cc0d252022c561566ca492327efaee43f294f42c95f87499c302dbdeeaf0bfe29ee2d0b00179fef4f73db8737c12eb3b5cbd44882d442c80170000000000ae22e96efb4e1ffc000cf03e01fc000cf12b01fc000cf6cb00d47c40c18e5a783a9277314480c9c0512a8fe825ce7f101b7f075273c892063b1b8571311737a5767f95c0f808aff27883260bfaf9cfe2b84519a6b230926eed90600b93cd05453899e96db8dfa36d2c71c3209e1660738c6b3af11473b5169c8f8dfacd89ad1bc92a481978f700000000b037d52073d1e445bc2fd41e35be1c52426e00152e49ffa55b6fc20f33b28483000020b037d52073d1e445bc2fd41e35be1c52426e00152e49ffa55b6fc20f33b28483208384b2330fc26f5ba5ff492e15006e42521cbe351ed42fbc45e4d17320d537b0014e6de0e472aa530261d5fbd3801d6d777aa7338e00000000010000000000000000000000000000000000fc0001e7020001fc0001e7100052254c6cd12c657c27876bc3c0a7b82aef45305fbf9ef9d3fee586e471698a3f70eaff9dcc96ba84a58bd603afbd1d6198ee831cefe1380b073a24d53009a5e37e3b9e556a7d7fe7cda1b54682351d4d1f6ecd331d98816db0696a5389c4a09bfc57f66f0a27120302ceadb07800000000b0447996025ff084c1fa1e0fc755b32d540143fed28b89791789fde2464f9f2e000020b0447996025ff084c1fa1e0fc755b32d540143fed28b89791789fde2464f9f2e20502fdd2e5de1a8c6ba9b4bfcbd14bb30743353814ee50e33f80c2e063a4ec6ef0045cf243bace96dcc31b4311405a12153630969330000000000235868cffb4e1ffc000bb3b40001fc000bc78300692790b0e670372748d3029fce2bdeb14816c27e692790b0e670372748d3029fce2bdeb14816c27e1ec5c66e9789c655ae068d35088b4073345fe0b03019f2c10770cebad591eefa4fa1e71d2baa7213f7bfea0d7cf6fc9313df3a6095f480b7eedb63ce8aabe16dfb418a9f0000000000b09c47d39537078986e4639420ce87b32039b17d80ff4eb88238c27fcfa1abd3000020b09c47d39537078986e4639420ce87b32039b17d80ff4eb88238c27fcfa1abd32040b9e1633d6a6c0a38ef14d5590c5cba47ea35c13fcdb2b1b86d08f2297a9a0400d8a0974e7667d17dd9a12a9fcfb313a13c918ce7000000000023a97188fb4e1ffc0002198f0001fc0002fd2400c7ddc0f64cab219e4119020d7a9c0ffea17b9ed0dc7ad6d9a56d9e5370352a41c4b9b55601009064253cae727106faa4bf76b0b4f8375091889f6715301848a0024f4a1b85e18552105a7d397714bb9d16a392a29b5d6d18bba91fc880a6b20be09f1400dfe58de3ea87f919ba00000000b0aee43d5964ae06a7ce63c03332d9f1af46386b91738cbbfdf42f67db488c5f000020b0aee43d5964ae06a7ce63c03332d9f1af46386b91738cbbfdf42f67db488c5f2046674ef4c6ad3a94ca837fdda85dcacd4e685f2722cd1b33c26505a95faad46e00976899eaa0087e8b7daf0d688fdaaf2197da58c4000000000022e99becfb4e1ffc000384320001fc000608030014cc95cebcd011e38ee7a83fb6ea445ff8ed0550177f797c6205c1997ff1ffaaf6aac98c13d865ddf32bb66d6fdcd07b1268d21a3e021c9c954452933090ea99287802a44836309be934ed63933b423580626adeb428026acde6bdb283f370ff19bb37f81b0e4775187ad006a300000000b0f7021cd2662eb74b1802ba34fef476d176e815569aadd4931bd4288f5256a8000020b0f7021cd2662eb74b1802ba34fef476d176e815569aadd4931bd4288f5256a8201b6c893a523e3fc81e071e645926300e1a37d71f02e1bbc3aaf75ee1961bb56700a445f904cfb88572a605f98fe2826aacf9bcf268000000000022d91746fb4e1ffc0006567a01fc0006c05c01fc000bdc0b001a238d7bcdd356d52831c991b56beb9a50a986541a238d7bcdd356d52831c991b56beb9a50a986541ec5c66e9789c655ae068d35088b4073345fe0b0309247cd1a65f03a854cf5c9d7ef6c606d5a8789ddcfa7e2f04ec03d6c93b365a01d2f302f1c93aff66f33d55fddc721ed00000000b149c50e97a1411b76b2e26ca20b9a6a317d0afe19df2b78b967f0b94aef1f38000020b149c50e97a1411b76b2e26ca20b9a6a317d0afe19df2b78b967f0b94aef1f3820595c1fb1f5d3ec30b832c9c3cd68e19b4dc85334d0dbf734671e3c38844c8513011fdcb249be6d1f0896ffd3c5965cac5f087864d0412000000034235351fb4e1ffc0001991e01fc0001fa4501fc00038bec002adba90fd804d6d89438ea6729608d5276687fbc2adba90fd804d6d89438ea6729608d5276687fbc44fdc27a48f627d31adb54f482d59e535c226de0308f60f80538f335ba0f9f5452f02d7f5527652671da80c3d1c10e31e040f9b901a53b476a9ce02b507958bc8a65acd7b0018b3277a4f4a3667225def8a4f83000c086719cd9000000b1b3f7b8e4ae179563fc3cf3bf51148644cf9e38256a06d73d31050ebaf486e4000020b1b3f7b8e4ae179563fc3cf3bf51148644cf9e38256a06d73d31050ebaf486e420945e0ef94323e11ae3c6348c22d0106e35d724c00bc81c70956bd98d42a46074009b3193d314bfd2e375084a1d45eb689ccad9c2dc00000000006ca0877ffb4e1ffc0006fcd40001fc00070ca3002986dbc41a156ebc9c49fdf1d1842a76f21044b7c61ae923d66d3e7a9a82b85fe5eb375e966b109103650c94f0e6f7a84dac1089fd0f6dac2aa7b4ea300d7a075032c423dfd82adaba63256db7c7a0ab10eecc99544fd628e76840759ce5fc0f27ad83197f464371a1b353095200000000b1d373e438cf455c8297ff3d8fd1b27a1be7365dc55bdc963d0c02930338a519000020b1d373e438cf455c8297ff3d8fd1b27a1be7365dc55bdc963d0c02930338a519206a67f98d40507765c2142f4d70d3133a428859b1d4eb7f7c702d82781350b7b8016cfeef7175b7dd90412dc38d3cbb55a5da930fd9000000000034281b0efb4e1ffc000bb3b40001fc000bd23300ae5ae49de2bf939a61037d1ab3c9aac1528a8034ae5ae49de2bf939a61037d1ab3c9aac1528a80341ec5c66e9789c655ae068d35088b4073345fe0b030874adb6d0e5b65105e507f97944c24c90c5120d804ee0f36c7079c7c7c2f86aec079d13392b583e0553b699dcfab799400000000b27a788d5106178e1e365336ba2a53d6f0e4a48b76eab2faf3aac12123473740000020b27a788d5106178e1e365336ba2a53d6f0e4a48b76eab2faf3aac1212347374020a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e3b6b2d6b24f4fb4800563a0c581278ba501dd5b46b0000000000235b8659fb4e1ffc000ccadd0000002d0ac80af443e477060c785066014d561253d22d2d0ac80af443e477060c785066014d561253d22d64f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d73000eb80b32b60db5d7b03559f6e9205beac8d047689904bdda0bc50987d5f208d39b78ed90a34af7e1e9d44495ca1eb4200000000b2f62d6812c31f4f46265267da924e38395274e12148d979e4b4759035b26072000020b2f62d6812c31f4f46265267da924e38395274e12148d979e4b4759035b2607220a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e06083c6d6b80dea08171cdbe3134fa90e5dc9711c1000000000022de5512fb4e1ffc000ccadd0001fc0010df0300a3efa844b6dc22d05e802ebd5d1eb02cca122c25a3efa844b6dc22d05e802ebd5d1eb02cca122c2564f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d730075b907b6d6c12aa111da0e102186b9d06f4e065969b60732207f18c2c5d0deb8ecba47cb4c0929647db0e2fae6f08ca00000000b3004b53adce8cdf983830857449bb18787178023971a621d988d360b703e529000020b3004b53adce8cdf983830857449bb18787178023971a621d988d360b703e529204dea6406996a98efea88a66bddbe7f9568093185b08c865b1b664ae0e594c7be010eac161c360c57015ce83107d781b9ed935d3edf000000000008090a0bfb4e1ffc000cf63501fc000cf87a01fc000cf893008a69e5fe65c9a67e214d84a116b441abd5f9aad38a69e5fe65c9a67e214d84a116b441abd5f9aad3c69a0bda7daaae481be8def95e5f347a1d00a4b4308fed7a63ded7f5de0bfee9808589940f1148f47656d017a1fa77642352b5348ee318af4ac3fd63fff3b4e5c55ac1624b00000000b3b5748571b60fe9ad112715d6a51725d6e5a52a9c3af5fd36a1724cf50d862f000120b3b5748571b60fe9ad112715d6a51725d6e5a52a9c3af5fd36a1724cf50d862f20593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c1689fa69f20934cc3ede9dff4589af59c19a14a3f70000000000342b0d5cfb4e1ffc000cf99e000000d57dc73bca0753cbd47bb33f68362ac13e6daeadd57dc73bca0753cbd47bb33f68362ac13e6daeadc69a0bda7daaae481be8def95e5f347a1d00a4b430816ab3f50007333bcb40445130cd0e82139f8c68b592001cd686efc15e303206491fada6cf90af8f24a28b81a9b59ccf000141b308f737ca9e39f67b553158903198a88c516e01fb8f3001fb05a3b42fd6e07095c8b1c88ac52a22cd97d8ebb051ba7adf401896d8aebf04db1080000020b42fd6e07095c8b1c88ac52a22cd97d8ebb051ba7adf401896d8aebf04db108020a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e71fd01a6dcb1e645d921f8e714b2181c90b94e1a24000000000022dc861efb4e1ffc000ccadd000000b4fb462bdbb65e1dc1380a1d4723220a09f3b4ddb4fb462bdbb65e1dc1380a1d4723220a09f3b4dd64f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d730088905cc3f99e76b3a1abf714a55978d9930c2abdc77a21bd809e452e8c47c35d38e318ec3118e1944cf1a4a8df907c100000000b43dadbd485e4d1e1d202ea5180f0ad4e8e7f05e97a7e566a764ed714356bd1f000020b43dadbd485e4d1e1d202ea5180f0ad4e8e7f05e97a7e566a764ed714356bd1f205c71e5f46d35196e33b45c5d59d3fd2dc84381942064cae21744fb717412c1ac010f673549b55f956f58bd209f0cda6e0af0d65b2d00000000002f6fb5cffb4e21fc0003c5f80001fc0003c6840099e9dff4cd5a0abc61b5287a0ba48c0553d6358829dcf16f7a66b832d3b84dbab400a1e9eb7f30ac955410003527bf2b360a7a390b9ff14b9106c6323090c0e9ec9dc5f08b1d4d0211920fe5d96a225c555a4ba7dd7f6cb14e271c925f2fc72316a01282973f9ad9cf1e39e03800000000b4ba4ab73c3757ba9cc6b6fb98020b854228be7de4704ceb7da02e7c6a2ad741000020b4ba4ab73c3757ba9cc6b6fb98020b854228be7de4704ceb7da02e7c6a2ad74120bdfda6f0bbcffdd7aa32a0b762eb6506cd719d88cf5f272d1ced2485a6bcc9ca0149ffc6acbf7ea405fb117bfaea252f885c6b6ba300000000010000000000000000000000000000000000fc0001b1ab01fc0001b1b001fc00021efc0064cf453213924a7f394eb5ff3be693174b8d0d983db6e109e8d2e2f052216a47568b8881f7df245bd8acf473f417dbb62954adab796af04a646847b13000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b4ef45b7d0b716ffa761809326697a6420365e1d137b52d7d275e7f326280ac1000020b4ef45b7d0b716ffa761809326697a6420365e1d137b52d7d275e7f326280ac1201eda6d2f8839ac6331393c4c9e2c97ab17fbd99ee5bf9f02b3ab288d60aeed4101c829eedbb02f90bd3a33dcbd225256ac75e2298c412000000050d1e860fb4e1ffc0007d1da00000064cb3ef38948917a58eca6dcaf03c4d94a3219011546085b56803db4366c2059d4755c8a28796ca30d5bcbeeb459af40f97fcb4a98e9d1ed13e904c8300450dbbbe82df6808151b83a46f8c531cb240eccfe65f8f0b49f3717056da7268c14e45f0dd14fff8daed28fd353c1b401c623e2d926af5eb52dcc2b931993d3e527145118000000b4f9de65ae676b63f84f2865317b8b512a12516c4459f2f59ca2626c71f7dda3000020b4f9de65ae676b63f84f2865317b8b512a12516c4459f2f59ca2626c71f7dda320a3ddf7716c62a29cf5f259446c51122a518b7b3165284ff8636b67ae65def9b401f9a85a965fd3f6ea024aa1af9af585b3993c2882000000000001010101fb4e1ffbed7c0001fbedb2002e57d3d0f052b955f247a5c1d4a41266cf5bd93c6960122148b84c5f044a812c35d5380281a0f02e88a052d5925781c116dff6be4f04739113c0f9a430016a16472319f62f71bb60e38038aa8cb93a301ff6c3727f75f4d770428d71d032fdbd27c5d03dc56ef1d658fefe795400000000b55a74503e30b3f3066ef0d94ddce16cc7f87831a4b782764b588e5575382a88000020b55a74503e30b3f3066ef0d94ddce16cc7f87831a4b782764b588e5575382a88200b18bab21b495a6bd4d872e3fa0f87e5ec27effa90d3c58cca27843d9d96da4f010f4af69185db513ed69f7538a80cdf50cbf6ce2f0000000000235902aefb4e1ffc000bb3b40001fc000bce4300b6bc771fdb7d72115152872d2809ff854a16c4cab6bc771fdb7d72115152872d2809ff854a16c4ca1ec5c66e9789c655ae068d35088b4073345fe0b0309489f888b6bb2b9aea1dc7580c45a7e38d3d3f197ab688c48962ef102588017558d6bc1ad8bec667892b2436e64ba50f00000000b5706630cf1c631b5f95edf39d0fa1fcdaba9d34459b0b392e3f28eb59ae90f6000020b5706630cf1c631b5f95edf39d0fa1fcdaba9d34459b0b392e3f28eb59ae90f620f690ae59eb283f2e390b9b45349dbadafca10f9df3ed955f1b631ccf306670b5016c87be22108a3287243c4bfd060433101cff516f00000000009de6137ffb4e1ffb602001fb626c01fc0001195600d157ab8fe5436f4c7a475be8a35079b3aca6c5fbd157ab8fe5436f4c7a475be8a35079b3aca6c5fb6d4c795644ca86f717628ea27f0af13b0ea70eb730874b17058e37c39f770188dfe8e699959654d723e62e28b2760900e5284f63f6b70e077a6ea9803714bdf62d083b1d9e00000000b5c0d248eac5f19d665159412f357073359d0d643930adee1d071f02e9ad0a1f000020b5c0d248eac5f19d665159412f357073359d0d643930adee1d071f02e9ad0a1f201f0aade9021f071deead3039640d9d357370352f415951669df1c5ea48d2c0b501ab386459f5642306e5993f9f7584fb744de7076300000000010000000000000000000000000000000000fc00025b7301fc00025b7d01fc00026ef0008923f5540c3cde8ff5f57178422303c469510c488923f5540c3cde8ff5f57178422303c469510c484deccc4867afa6d1f8e500e66da4f136e46638b83000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b5d5c145d244a98b81cc9b5fa2f841cb6689e7cab76566fdc66ba16a82db95a5000020b5d5c145d244a98b81cc9b5fa2f841cb6689e7cab76566fdc66ba16a82db95a520dd55abceed2198b21aa5486f47bd0715607d41c79b75aa3e3ce3091b57b46f020159b77252b432ccfd639e3d1286a82a8700f91a4b0000000000336b0426fb4e1ffc000386690001fc00052bfb002e1496064dd3a7a8c0a5cda78f3b4a4073ffa2392e1496064dd3a7a8c0a5cda78f3b4a4073ffa239a6a050bffabcdf986e775567e1ba53dddf578ca1308f4fed7576bd1e31d45225788c1c96836dbc85b3ece3b77fbe4ede0f5f784f138ef6b32884e3345915a758364d1e582300000000b698b5e762f0d11faa437d55b16ca54722ba8ddb0b3eef0256ff80354f0c8d83000020b698b5e762f0d11faa437d55b16ca54722ba8ddb0b3eef0256ff80354f0c8d8320cb53246d5a57694cf7e19868540214769b2d7fad12f824c47130244873204e8c00a80186b44321096c4c5997ee6358e220bfb3d6ce000000000012c3324efb4e1ffc000d62c20001fc000d62fb0023142164ea1319cf4ad34e8fbd273c5502d5dc352e3252f64967541fc0092b78aac3dfbb7fdfa8d2a90c41d69e6e6132b5433b45a661b5f2187458a130a90febb8c2b031ae7ca222debc10f12fa0a71fcef84e2d92f13c1ad192c42e371324bbb66c86e24434754e2864ba14ce00000000b7c7c32bc7f34cb18da6b4b3fa53d8a6125d6f6dec3f7849e728bc8f89eae495000020b7c7c32bc7f34cb18da6b4b3fa53d8a6125d6f6dec3f7849e728bc8f89eae49520e7365918822860b9120091cdf14e16507de20bb5dcdb6784b16352c2b66ba700008f6273f09406792bb9b717499634ecd4446db449000000000036cb0d93fb4e1ffc000bb3b40001fc000bce5b00563f03e344dc17a7849e6320f56c13b0b5c32cb7563f03e344dc17a7849e6320f56c13b0b5c32cb71ec5c66e9789c655ae068d35088b4073345fe0b030011bc68f6561d4a7d5f7c1e6fe4742d8ce2bfec24576e40c8eaec56b3759bdb5be5e6b9234c77475c74be1b0466ad9e400000000b7f0ada8d395f428a1a72db04b76caa042f7020b2f90641fcd1499be6c37fc9e000020b7f0ada8d395f428a1a72db04b76caa042f7020b2f90641fcd1499be6c37fc9e20a3b41298f1b62474eaf528e96815202beebb6eb5751f0b495a7ea49ec6aa04df0029ab2ca57c2c3d3a756db61eefa71cd784a7533f000000000022d536e7fb4e1ffc000bb3b40001fc000bc7e300538584030db46ef33cafa5765401d48e0b9fe6b9538584030db46ef33cafa5765401d48e0b9fe6b91ec5c66e9789c655ae068d35088b4073345fe0b0301802f2a1951734dff2eaf714cb8de115a8df7bbae8da6a1e1bfc9c0f020908cf68cfb2f5efaa4412fea5116db12b569100000000b9e4c7189d01f8da6eb8bb5f4b8f8c2a0a24293d0f6e900aa0371bc32ec6021d000020b9e4c7189d01f8da6eb8bb5f4b8f8c2a0a24293d0f6e900aa0371bc32ec6021d205ab2eb7a853640b8282676a50464bd24596d3094fbe40afa6d2159a6ea64488500db4c10c95bbf83225e49ec3967653007708d8d8b00000000008b3b5692fb4e1ffc0001167b01fc00011b9701fc00011c1b00fc8511ca8de4f660ed57620e4537737e55622bd9fc8511ca8de4f660ed57620e4537737e55622bd9db4c10c95bbf83225e49ec3967653007708d8d8b3098bae0f71cbb77fff1560f45680ada9492ec4c9f779df777754b54bfb3474729c269399bd3cdfc736866364d3fb011d100000000b9eeb35f00d10ebde45a23db94875bed007b94eb03cd0317ff721e24dd5363c8000020b9eeb35f00d10ebde45a23db94875bed007b94eb03cd0317ff721e24dd5363c820f9ada33272169ea08ff6161000b9fee6eb81785cc491b284a2acbb87738a330f0139387c3d869b645b7700d9e16011681c0971cbf63c23d70a009de62866fb4e1cfc000283a70001fc0002ad4400caf26da61833c492453bc2d74c6dce3d91e2c38fda5ea047322750daebfc463a87ec042108d63ce9d458f5157d91f4832e66eb8630ab3dbff95551d8308f420a082c56b30c9bd8492394d83066a8d03628a7c8e3eac27486377e2648bdb3cebcc4fdd16cb4cab1341e480fa43900000000b9fab136129b05d86ccfeee5298f207ab2d76131af41987baccf55fea5efb4c1000020b9fab136129b05d86ccfeee5298f207ab2d76131af41987baccf55fea5efb4c120a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e2542293a57d22c1f9064bb876ef27b3f4a9e5824f5000000000023a21274fb4e1ffc000ccadd000000289d0729f182f703f2df4990b51e2b103515a32b289d0729f182f703f2df4990b51e2b103515a32b64f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d7300fa5377eb256323aace31b45c3e48ea110404b053cb80e8043bd1e44de1705130548e4ab28738816251ea57a7fc1032400000000ba8ce1dc72857b4168e33272571df7fbaf84c316dfe48217addcf6595e254216000120ba8ce1dc72857b4168e33272571df7fbaf84c316dfe48217addcf6595e25421620593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c1488164ceb25e5c05e3192511d2be4a5ac103cc5f70000000000342aca80fb4e1ffc000cf99e000000ca94dd35b74cb251457e475dd7507055eaf1b4e1ca94dd35b74cb251457e475dd7507055eaf1b4e1c69a0bda7daaae481be8def95e5f347a1d00a4b430acec7bbead86221590f132810b8262cf98c91b338927907b86bf48baa54dd1912bfc1f6fccd069052cc8c79eb9e8ed2c000162e0104ce0aafc1f06bde37c73702fe84b307f0501fb8f3001fb05a3bac184b9f1e4eb098d1f8df0b07af6af8919c60c1f60e31ba29c2f39f395ff22000020bac184b9f1e4eb098d1f8df0b07af6af8919c60c1f60e31ba29c2f39f395ff22207186875d6669311c046bc6052538390054e2cebd21b2eaa908af5a273602fe1a00d97799fa72f75b2cab264f40eae80856f27f6f10000000000003dd1d17fb4e1ffc00021c2901fc00021c3c01fc0002712c003da6a63a5f595ab15da44601749453c0ac0b8b7d5519b11029baf89428cad6fd4e70e3bb09f356f1d97799fa72f75b2cab264f40eae80856f27f6f10308bf25d66d63197e3144f6fa17ad92ae38cc11b143027fb91dcf5c20fde6e52bde7f46f2789e6fa84573197d8085389dd00000000bad4dcdc0ec1f274f70f87a3f4509096e7ba517adef56a4121a20f665d5e8e7c000020bad4dcdc0ec1f274f70f87a3f4509096e7ba517adef56a4121a20f665d5e8e7c2076a391457a0942b72645223669feb8e22db6e8ec7d9056eb5149f5689cc3e0c40054a71d0e91f24c449a09b22c0f77e6540261a5500000000000235ae333fb4e1ffc000bb3b40001fc000bc7b300a14dca43f5ef41a8a4340a62787f0901e54e8adfa14dca43f5ef41a8a4340a62787f0901e54e8adf1ec5c66e9789c655ae068d35088b4073345fe0b030848001b4004d5e5eb6782bcf3a3b62c2d14f237af0be67c10d70d84be1a28142bd5edcf4d90de08af31f8381510ff61600000000bb889ccdc43531f927eee1dbf095a5367ea314eb44818be2277476617af7d35a000020bb889ccdc43531f927eee1dbf095a5367ea314eb44818be2277476617af7d35a205ad3f77a61767427e28b8144eb14a37e36a595f0dbe1ee27f93135c4cd9c88bb0176e71a262cca9f6667bd35b19f182ba67b44c9cb000000000059280381fb4e1ffc001094df00000059ba7af9e92023a6b1160a0a45aad2dec70e7cd703815c232820445f311d1192f578077c1cdd3b540d5bcbeeb459af40f97fcb4a98e9d1ed13e904c830b529e500f236ee90a3e7c274dd51ad91310561f10d066560b0f28922634fbf67f50660e317f3f4c06441fa5ca98775d900000000bba99873df74a78b6fd5150907b216eafe16816006225a4912affea3ffb41e00000020bba99873df74a78b6fd5150907b216eafe16816006225a4912affea3ffb41e00207b744d5c91d46c013969caef13e72e56c6ae7bc89588edee53cf4ceb6973a2f50120120c7dfc6f165a4f2c104d6febd11c496069c000000000006b16c782fb4e1ffc000607dc0001fc00062e430047c6566a13ba6a7f8c6a3cb8872664c2f8f4ee27dd3b064ca33829ca65c37e911259da50d3490ef3b508db53f0a3f072b00f579a86e813d6af2856f3301059c4fdcdc32d831534403f7e6587555d74dc1624f6e2bcdba10a099e6c4f8d5f31d4c270231180ded264a009387e6c00000000bbfd0ac1977011267a7032641ef5487fe15a4de798faa485b156fb3b7eb0acb8000120bbfd0ac1977011267a7032641ef5487fe15a4de798faa485b156fb3b7eb0acb820593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c060d8235767cb55972a30d653eb9dd10f51b3c46ec0000000000235231c4fb4e1ffc000cf99e000000f9b93e179a0c22afd92523427341b5e0b2c2a102f9b93e179a0c22afd92523427341b5e0b2c2a102c69a0bda7daaae481be8def95e5f347a1d00a4b43095c89af86eeacfe403684306c98173c2a59198047a778787887d34ad6b0c9b787d689a7c3cd9e9dd5d103cba70f3855f0001dbbebbc52a5bae21b818e0487311041c91b2683b01fb8f3001fb05a3bc77a5a2cec455c79fb92fb683dbd87a2a92b663c9a46d0c50d11889b4aeb121000020bc77a5a2cec455c79fb92fb683dbd87a2a92b663c9a46d0c50d11889b4aeb12120a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e5fd2b74b9987e80fcdd3aebe95721c6c4709724ee6000000000036d55ed8fb4e1ffc000ccadd0000002878a638db0682d49249ff8ca872f16653a84f912878a638db0682d49249ff8ca872f16653a84f9164f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d730174de56654f2bb6417e15ff06361ea0becc00bd72a3eba0f83b60feac860570769fbf28482a706f10906a1e96dae4a8f00000000bc9479593e38ab280b75dc76bb4d10483b1b341c2e792d7dd278c21d202d2b93000020bc9479593e38ab280b75dc76bb4d10483b1b341c2e792d7dd278c21d202d2b9320e9d3abf500bd0cba0f374490d4e0b3adf1dcd865da1ab04e8bef255e4a24ff630041796bb0563ff119ced9d76be68c0d5898bad86e000000000036da55d2fb4e1ffc000bb3b40001fc000bc7b300422b11d7511cab020721d07fa2d011bb1b7ae433422b11d7511cab020721d07fa2d011bb1b7ae4331ec5c66e9789c655ae068d35088b4073345fe0b0308f6e3e0e34f5afcbf9eb7077a3f0e5ddbc2902f5610447b9bbf871fd0065c8f156b514bc5180d579bad722d6112f1a3800000000bdd08cc998cc494d2e008405bd71d5917a64adde6216339d74be4d379c90ff19000020bdd08cc998cc494d2e008405bd71d5917a64adde6216339d74be4d379c90ff1920d5b7bf68c3d573cb8c592b4fca527b753ada034710ae8b5eeec83c426ab00dec01673a5871f70c41403b9fcbdcb7a7e2b734f3cf130000000000951ccbbefb4e1ffc0006592e01fc00065b0801fc00065e350047d2c552db05fdbee9a78f346a8bfbdfbbeaa5a068eb72f005d366e18db38f638716d97bf60d53c7673a5871f70c41403b9fcbdcb7a7e2b734f3cf133003d325fdc665db2900c24c0736b927b7fa7ba7068c9595991e6cfaaa0f8e1269a31f6d1da2b85fd922186a9979872cff00000000be563f5793f34f16e6653efd9060c4042b492cbf676cdc66f9d68836f078b71f000020be563f5793f34f16e6653efd9060c4042b492cbf676cdc66f9d68836f078b71f206a0871d1bd82667b5df31b0c09861a71061f9fb1f0df3c2a8ad0aa11710100410109c927a4a7a41ffdd8cfe3f780f5108a6ffa1c514248000000c3c925fffb4e1ffc00062ecd0001fc00062f6300c5775227677d9c67fb4c13795a2bf9d80ea231c9304c46d5f01a600ba66e3dbbd8bf6dc23e8c5297aabc8c5bbac24daa81a5f2425983dde53230cc203093612d652fabcdc0052e5bde98d276e49ea71d050a323b98c368a06742fd964d21f567e16fbda2c17b00adc470f6f61400000000be89ade2107051d4f50cbf1d99338d42b33fa7efb079e14d906ed9b518768d36000020be89ade2107051d4f50cbf1d99338d42b33fa7efb079e14d906ed9b518768d3620f2cacab8a192994c64ca14bf7a9d1c045a8234e615dcc6764219af3b0705adc000e6996e06f219509dce93957d76e2fde11a5958380000000000341bc6f6fb4e1ffc0006568001fc000a68af01fc000bd4aa004d0684329ab95dd4ee2c0d275ef313bc0e0adaa24d0684329ab95dd4ee2c0d275ef313bc0e0adaa21ec5c66e9789c655ae068d35088b4073345fe0b03016c6904fbceb7584e75ef553b85ca20ec8cbcb1ac49d985b0cb77760107753205415c4d5cffe3be0a10219d0dea98e2200000000be8d0533c692cf23e3d3eeb3957422b5a98acd82aadbf7baef255edb2f491b82000020be8d0533c692cf23e3d3eeb3957422b5a98acd82aadbf7baef255edb2f491b8220821b492fdb5e25efbaf7dbaa82cd8aa9b5227495b3eed3e323cf92c633058dbe01c428ff31ec6308043a7b282eed63d1d8920c2d8300000000010000000000000000000000000000000000fc000293b401fc000293b801fc0002b6e70091b4363730ea1c02de53aaade78508ee41c38f9c91b4363730ea1c02de53aaade78508ee41c38f9cc4097f46f9eb0990bc7e22d3bb29af6eb76d94d03000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c08b723b79a7139fa7097bb85b4d0dc387097cf2ea66ad34992b60e1fdb5df1e000020c08b723b79a7139fa7097bb85b4d0dc387097cf2ea66ad34992b60e1fdb5df1e20c0785da69e10c38185460b8c938566484f113a1bd42feed2e03b8a76567f6b820024ecdc76f0781a35a9a47762313f63c5e21ac0fc000000000022dd41a3fb4e1ffc000bb3b40001fc000bc78300a7afe89589507a716dfcd88009d108734edddeb7a7afe89589507a716dfcd88009d108734edddeb71ec5c66e9789c655ae068d35088b4073345fe0b030169fd77b3f11dd8f82c03ed8b79c1d986fa1445e6f726b0c1b556bb884c83890339733b2521630b8ae57c1428d0ba12c00000000c0aae8ab24aab988cc84385d16af7ffcfd365d0e016f5799759e0525a435a617000020c0aae8ab24aab988cc84385d16af7ffcfd365d0e016f5799759e0525a435a61720a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e355f1d75bff42c098ef3598a9a5fdf2aefd216ef66000000000036be3d46fb4e1ffc000ccadd000000ec74aec7dcccccfaec4c5fe65166a2d5ce0e3268ec74aec7dcccccfaec4c5fe65166a2d5ce0e326864f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d730892a3de6fe305d39d81ecc9dbc7c85bc6eb57434618903f45ac8996aecfa9a7945e2cc48c40c1540172096229780519e00000000c0dc1876eca746f08e401c7873260e277baf0096a0b19e519e6298b649dd23bb000020c0dc1876eca746f08e401c7873260e277baf0096a0b19e519e6298b649dd23bb2025ab3aaf757e9002b95d75ddc9f2ff18ae237e53a8e10a93dc47fc163bc91d120128c20f725ddcc44c5d6c728b05b886805ca125af0000000000b280576ffb4e1ffbc9de0001fc0001196300febd730bedac1010a2943dff1c796cc544609f7cfebd730bedac1010a2943dff1c796cc544609f7c477a52436b944f3e9223ac8404a7717d4176fa533003f959fdcb3eefebe409ee7044748f71ec8cba18a7a73df9d55d118e170d7ec2540d5c08a4cadc4bdeff3f7886265ac100000000c11c1168dcf9479475cb1355855e30ea75c0cdda8a8f9ea80591568dd1c33ba8000120c11c1168dcf9479475cb1355855e30ea75c0cdda8a8f9ea80591568dd1c33ba820593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c040cb28bcdc1d1a970b6255a04138f84c0ebfa52b6000000000036d5cc55fb4e1ffc000cf99e000000ec040cc1866da3e55c8ae6c0f739cafabe3f5cbaec040cc1866da3e55c8ae6c0f739cafabe3f5cbac69a0bda7daaae481be8def95e5f347a1d00a4b430aa910b9552857a7712d54b468dfcbb7d9e27f26a49e06fb1f0fb00dd0f5a1bf926863c25ad03fd49c56b62065ecd06e70001fdae7cdf38811659ce9481975b326a5d07236bc501fb8f3001fb05a3c1df04cbbc1c77ae3157c4d6b50eac093068c1acccccd1f6206fc6bb892e8bc8000020c1df04cbbc1c77ae3157c4d6b50eac093068c1acccccd1f6206fc6bb892e8bc82015bbe1f1af1bc27cff5a355b82d0c0aaaa5bb19a634fae26671416b39c92630f007a36078fcf52a03235ec5b11dcf012eb7beb356f000000000022da4cb3fb4e1ffc0006568001fc000b9be201fc000bd4aa000eaa20f14a3447fe10315f6891d24da0e44ac1940eaa20f14a3447fe10315f6891d24da0e44ac1941ec5c66e9789c655ae068d35088b4073345fe0b030181387e11f86685b42d5030cf61959e3005d1c328556c83637e4a0acaeb62046847d6260c968ab433c9c6c946d170ef800000000c226d6e2c423eee0bf233ec020c8012b6ccfc1bd5430a02c55613eede35e9107000020c226d6e2c423eee0bf233ec020c8012b6ccfc1bd5430a02c55613eede35e910720bfcb8e882baba43c6975d87daca9b5223c9f8e6ca0ac9e2965c06ead3d89a08200c3063b19c638a44112f5f75c1d066261a497223c000000000022dc8349fb4e1ffc000bb3b40001fc000bce5b0001b9d16bb8176bc52aa900abd93b3613e5e91ca901b9d16bb8176bc52aa900abd93b3613e5e91ca91ec5c66e9789c655ae068d35088b4073345fe0b03017ccfcb2e59e9efd15cd4096192fd937119581523caacb1320afe058b2784b0668e4831bf6e8e79954cd2118d1b0e45700000000c2a54c1ad133acbf3366aba2534ed6c1f01728553a7e877ac2a22c98be085c68000020c2a54c1ad133acbf3366aba2534ed6c1f01728553a7e877ac2a22c98be085c6820bf623c10780b9dcf9e60e181c82b093884f950faeef2c50c9b268342b182b6d301b528aa08346d887417ad542b2dcaba998abb900600000000009de66e56fb4e1ffc00011b610001fc00011d6b0007b48a04d0a73deac14da9df36ca49ffb142339107b48a04d0a73deac14da9df36ca49ffb14233916d4c795644ca86f717628ea27f0af13b0ea70eb73085f01c97f8e6d601ed269d4fd1d33b456c5c940aecc45b084c0f8d9ddac26d6fb7c5cc1eb817a41bca401e5c9c4ff85600000000c321458ad5e9517e64583facbe4ee3d0694ab856377fe216ab2f4bca85cc2f76000020c321458ad5e9517e64583facbe4ee3d0694ab856377fe216ab2f4bca85cc2f7620762fcc85ca4b2fab16e27f3756b84a69d0e34ebeac3f58647e51e9d58a4521c3003e9257ce8103b6a3836bd1e6eb938ea1c04efb480000000000ae22e972fb4e1ffc000cf03e01fc000cf13701fc000cf6cb0044e7c4cde18464d480d28b52fd7d23ffa72d128bce7f101b7f075273c892063b1b8571311737a5767f95c0f808aff27883260bfaf9cfe2b84519a6b23017a49cea05ca2e18f74af110c5ab52c89a43ced4e056a8af7ca8973401494bdaba26d1c56b46b018091d0dd64f24475000000000c36584a1242574644c1a1620703c55200cc0158de276dc388ffa9815ec328c31000020c36584a1242574644c1a1620703c55200cc0158de276dc388ffa9815ec328c3120c6db6a114efbdf794abc8a68954f6005393aa508ff4ba392eb913aca117c8509016dcc6dfbd52edfa0d3cb1b5d503c5c7b00f05d83412000000023a3e220fb4e1ffc000197ca0001fc00019a0300f4c0fe75eec22907d6b043edb0df74ccc7b85a45f4c0fe75eec22907d6b043edb0df74ccc7b85a456dcc6dfbd52edfa0d3cb1b5d503c5c7b00f05d833008b4c1a8b9c1402ea84afe7c47f7e98d657df873b9747a0e4a497120ec62c81f314ad91a6f3384648e7e60f2734554f700000000c367704082306916bf8d0dd2dfabf778c701ca6006a55b56de4e55a0ed9e2f02000020c367704082306916bf8d0dd2dfabf778c701ca6006a55b56de4e55a0ed9e2f0220a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e4b9b98f6b2dadc95391afc16b570bf7e3c706d796c000000000036f54b2ffb4e1ffc000ccadd000000df89a7a4e97a87e090c06cc44cdf6f596632e62cdf89a7a4e97a87e090c06cc44cdf6f596632e62c64f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d73016ca29d03ef4897a22fe467bb58c52448c63bb29534502305e8ff142ac03907fae0851ff2528e4878ef51bfa3d5a1f2200000000c3f559e803f09bb261a5f94a5c020816a4ca04627d1969819c32026d46004816000020c3f559e803f09bb261a5f94a5c020816a4ca04627d1969819c32026d46004816200525bd19daef243898853c4ba419ecdd8e493fa1db91277e6e4de61697438d2900c9a47526781022a84b503301b47c4c277d0d7d700000000000340c2f56fb4e1ffc0006567a01fc0006c05c01fc000bdc2300072732cc8d834a9c3cce0d05deffb324874388ee072732cc8d834a9c3cce0d05deffb324874388ee1ec5c66e9789c655ae068d35088b4073345fe0b0309757e077c72c5dfc02197ea345b361d66f861a16a3d506b5a99493929b7b42d2af420fa73b5c3728b8995d19b5952c0400000000c43b8e35d23d9cb0a088b5153414a204f436683298ad311c9cf2643cb9e482db000020c43b8e35d23d9cb0a088b5153414a204f436683298ad311c9cf2643cb9e482db209795d0f8c2ebc027150b12624db495b54580e283674c062f680b136e6477683801e8588af19dc9a7724451f1ff8a506b30cd18ff8000000000008d47264ffb4e1ffc0009235801fc0009a50701fc000a95e300c42520f12ca094d0c840ec18eaaf497adda92995c42520f12ca094d0c840ec18eaaf497adda9299521fb41623befdb80651c8eb65b8dfa90f1f507993081ace6ff9442d477f7eb80ebdaa666804cd0c1d6cb131838847f75cd83540eace2c501484adf0333b847ddaa6c087a8600000000c4b4329ea9e95851296c2c59d395399e36e2f0a6436d3a03cec8de73f35dd121000020c4b4329ea9e95851296c2c59d395399e36e2f0a6436d3a03cec8de73f35dd12120a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e2d4ec0d7b93616ff664078c9308e0bec4c8284cfec0000000000235c8f07fb4e1ffc000ccadd0001fc0010b8340020b99d09dfcc0f9b69fa97738487f20cc6c5786820b99d09dfcc0f9b69fa97738487f20cc6c5786864f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d7300196970badc74d068ec1226ffd4a656313decef59d792237a32e6ff56cd4e43030c436025831a4a3d0306a616f03381000000000c54b7009fd21294b6bd144e1d8b12492cdb0d2fe3b78007aa29142a84bd2e5d7000020c54b7009fd21294b6bd144e1d8b12492cdb0d2fe3b78007aa29142a84bd2e5d7204dea6406996a98efea88a66bddbe7f9568093185b08c865b1b664ae0e594c7be0238c1a1bec916b5169f94d1600c9062c9e44b62d6000000000036b95180fb4e1ffc000cf6350001fc000d08cb001e8e94abc60514536d80abdcbd1f252523eeb1941e8e94abc60514536d80abdcbd1f252523eeb194c69a0bda7daaae481be8def95e5f347a1d00a4b4300946837d177bd2b042cf1fe665aee99844afcd270601fdc4860231b9cc97909ccc214adbd2406ab38045d4465e3d1d5e00000000c582fbac1ab54ae7b5c89bd0bd92fdcb5e604bde4805e8ca5a61629cba7ef8d6000020c582fbac1ab54ae7b5c89bd0bd92fdcb5e604bde4805e8ca5a61629cba7ef8d6206ab54c4c60a06c2b59c05ce53c8a7939a128e0b8840d37132f13c3b84d203d11010625d7198a11ff1b8b2fdc69bc709657c2a1f7f80000000000035aa743fb4e1ffc0007b74b0001fc0008ac9b00bd63760f50bda0f3d8db2aeff88bc9eaa88596c3ffc45339be50b5953200438ba8c71ebabe9575e9ef0605d9bc9d3b3e7207258797498daded9527f63096153a0fb857c1da0f6bb1ce2e569bebfa14e6e1f532139f9dcb720d481db17999cbcd8eb66a5ab4c0fd20c5f9695fb100000000c6b291a26712b3f789a6f9379d55029d78f895fe3372c701dd5ef0a597be3b69000020c6b291a26712b3f789a6f9379d55029d78f895fe3372c701dd5ef0a597be3b692061f246afa7628f4c86905fc4f9063dba843830d5e5b9f069a6fd7981bb2c34bb01334f24c69a36c9adf8c9c644f9650da7a6655c3800000000002e65f354fb4e1ffc00053c1d01fc0005ad3a01fc0005b1f30033d78a9b138826acab6c464a74f84b9fa5cb23db5d068e0fe2b3fd8bf7983a2d806e797c522b75a9334f24c69a36c9adf8c9c644f9650da7a6655c383083152e6489f210094f5dd558373a1ce9abf36bb8001d4f35b3dea74f7ae74baf859abd22238c682ac94cab82eeb58aab00000000c6eee81fd38e6db24cb5e847794cefca7f3f8f95a066028bb8dfd6f36fb92921000020c6eee81fd38e6db24cb5e847794cefca7f3f8f95a066028bb8dfd6f36fb929212026101299b476b793ac0d19aee60267b583d670c5dae71755decbaab175c8afdd00c9f0eac27fa56e424e669e9205194fc9b173fdbb000000000068f8f27efb4e1ffb5ffe01fbc39901fc000119630038130b3e02c119f53aba29a12de6be40f0c6596f38130b3e02c119f53aba29a12de6be40f0c6596f6d4c795644ca86f717628ea27f0af13b0ea70eb730050f3a743867bf78d2e9a3906d15d8400d8d58255771d12828922386e8685f8aeccb8d9d81153f9c2d7da0436a71fe5500000000c7290309328d48982f4a265566615083ad72ae2e7cca5fdde599371762cd105a000020c7290309328d48982f4a265566615083ad72ae2e7cca5fdde599371762cd105a20c48677c8c69a59d52c2136a85090d3184e46f0c149bb319ffc2bc23d41e39009011a5f40c458858c685001ce69f201d3790b48a88e000000000036f4e7e6fb4e1ffc000bb3b40001fc000bd21b00a0d72e1d1296d2303c68aa6e148064a03e30dea4a0d72e1d1296d2303c68aa6e148064a03e30dea41ec5c66e9789c655ae068d35088b4073345fe0b0300422f6f4b6fb939bad0c5eced0d0085a9cdffe158b7fa0f5a4d83a2e311f080d92346f11764a2a8212196157d83a640b00000000c81c26dda720ccca323cca9a675257c9ea50c4aaf40cb1a4c2e931435f160fb8000020c81c26dda720ccca323cca9a675257c9ea50c4aaf40cb1a4c2e931435f160fb82066f6464e611b519b7abe070b67794d606b844fdfc365560468eca287bb381763014f6a74e089ab620cd7289a8a46a6564092782bb6412000000036bead17fb4e1ffc0004ee4b0001fc00052a3400e614deca3fce7919013e4e440fd3d4721ad3465de614deca3fce7919013e4e440fd3d4721ad3465da91a0b2b6a951742b8766f9a9554c313f29e86d83010d9901c0aa8f9b3e789a1413e731ff07b9b58d4f53925f53a1502f00e6ccf056dc86ffa5595a1ca5c02cbdfb38b1cb800000000c87218fb9d031f4926c22430c69b4edf1f0fb80c331c1a79e3b1b3873407c0ac000020c87218fb9d031f4926c22430c69b4edf1f0fb80c331c1a79e3b1b3873407c0ac20a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e3e709e0d0819c27bba7eb754839e873e9aae580b74000000000036b94585fb4e1ffc000ccadd0000005c0c201c793d6cb7265b6897058b0b1e75fdf5285c0c201c793d6cb7265b6897058b0b1e75fdf52864f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d730842c53c3aa11ae4b985a52ae6a3170bdb58f88ec04c62013f9322bd5fda4417939836b6f41741dd864c348103a1155d300000000c940d40d2849fe70baeffa8e343024d01dc80380f38b2a015798f503cba26d3f000020c940d40d2849fe70baeffa8e343024d01dc80380f38b2a015798f503cba26d3f20ab742c3f5293d67a1834b2506f41b1a36d58b09d713389e35d48beba6c145f620112521c58f53340f2c9569bf9e7d9c04f1b625a390000000000cf9afaaffb4e1ffbcc580001fbe61a008fe94ff326b3d3f9986fe97fb2eefa9a365629198fe94ff326b3d3f9986fe97fb2eefa9a36562919a86ff169d2789750a0bb4a5adecf343dbd10987230069dd3113d6320397e9674ba3595f46dacd562e013e9e80a2e7d1095525f35134d4a8c19f4cd4a19d3886edf6032875500000000c95f78ad5dab4ceaa98ff2d9d60d6d69e741f554b3ff876998dd832b2255a5c1000020c95f78ad5dab4ceaa98ff2d9d60d6d69e741f554b3ff876998dd832b2255a5c120c013351de51a56f7b39f2c10f3840e3fe943a174af4860f8e8665bb78247951501fdb9e309b9b441317475ef6c6bc6c1ea892d6a8c00000000002d2056e7fb4e1ffc0001a3c60001fc0001c433000e06d6f85fbf739967d628e48d87300c4bfa93e565b4b2bd9e302d32234a9bb205db6e51c08767ed1086f7c42d054d120f9ec84739e2211a19866e3d30128e20333b8b51fb8c72c2d5acafa049758b53279bf78f10a1f32995bd05d4f6313b2bd67fbc48379455d89ef869fa6e00000000ca0d0910002aedb97fb303e97b1db11583be62b3db8b6147ffa84b98309fce71000020ca0d0910002aedb97fb303e97b1db11583be62b3db8b6147ffa84b98309fce7120a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e4893f68af96d322ebc11029150d446a551042bcedb000000000036d45b94fb4e1ffc000ccadd000000b7e99fc3ee4cf3d64c4438fc2a61cba12c0e7319b7e99fc3ee4cf3d64c4438fc2a61cba12c0e731964f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d73092823797ad456d53ce1e6bde84e8a19164ff88a73ccd242ec48d9c6a479f2a049e214c7e8ec2243b7ea74ca6144ab2c500000000cc02c1be8ef00540856c769f77bca1afc593d3c40cdaf5ca033e462f1c43fc52000020cc02c1be8ef00540856c769f77bca1afc593d3c40cdaf5ca033e462f1c43fc5220a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e1423146e911e2951e98aadb67f0c40c8a21ed6bf79000000000023a1de4afb4e1ffc000ccadd0001fc0010d993001d92da27f8fd00226f85d9e1c2ae33f2d57b84361d92da27f8fd00226f85d9e1c2ae33f2d57b843664f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d73013146b3252f408f1cffc875b12b61f56c1ae02113b24c0b5aaedcda4a9b509332c8c4587450074f3e0906aaf3ceca75400000000ccc3668156451b3e10ac5c97d60e2c20fadf88c6266e3b2a9afb0e33e658734e000020ccc3668156451b3e10ac5c97d60e2c20fadf88c6266e3b2a9afb0e33e658734e20f9cdc515389213075782c4f03fad8a5010b7aa4165b804fbb1caae54c1c0f15700034ce75a5b9ab22d285c7876ccf1ea1ec4bcfdd300000000009b8ae253fb4e1ffc0005336e01fc00053d0d01fc00053e2c00d144786581a774e12dacc4aa155eb7d6d73869dfd144786581a774e12dacc4aa155eb7d6d73869dfda952b3b45775c0af85fbe2e2ab21549d86beb0a30057b3b0190261b1ded22b9c58550f7bf17a150de6a755a5478988b58e32bb7a53e7e6f9981bdbf416324e75ddd9853b800000000cd2963744e83eb775912b47e751f825f7fc8319db11f7ad4aa8e0f8831d12e09000020cd2963744e83eb775912b47e751f825f7fc8319db11f7ad4aa8e0f8831d12e0920f8659149d6af2d9b210531475f23dc5de3bfa2c35b45b4e54dcc471ab1b7222f0149343c1994d094b8ca7e095671e7aa7ce5cc141300000000002d200ceafb4e1ffc0006f1390001fc0006f1a300f6cdfba67f9b6228a325c80d5723557d8a2006d8f6cdfba67f9b6228a325c80d5723557d8a2006d849343c1994d094b8ca7e095671e7aa7ce5cc14133004ed653b556ea9d8b8391dc59ce49796b15c118e37daa2eb42326f72571b195cf21e814f93338ac9488000dc3d8b4d5500000000cd3fbcf015bb8071f253c07a4c5511e4759db5f655e2d198e4e2042e3986e828000020cd3fbcf015bb8071f253c07a4c5511e4759db5f655e2d198e4e2042e3986e82820dbad65a4c4cdae2325f1cf0f399a16a978c433a81e38987b8d9a5992087607e7019e5d4165c421b666fa97b17b6202fb4a3c34ed4941f00000003ccdda05fb4e1ffc0007663c0001fc0009419300742612cedde82b7e8d1f49ecc96cbd3b3c65372c7fffc5375fa606d4066bfd9f4fd211b3c5d59a955cffda7bd45f324d8b3b96059c999ac2d95044903091da7eb4d0d0f78e4aa5379d45c779105a0d809a04497186d53743876e31874d663f965507339259ce2b99fd3ea4c275015cffda7bd45f324d8b3b96059c999ac2d9504490000000ce09b01abb1fdadc8c04db6f8e9141187b034ae536776134e01156196fd595ed000020ce09b01abb1fdadc8c04db6f8e9141187b034ae536776134e01156196fd595ed20a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e64e01963565d4e45dd2c88567cbf3f1ba813737203000000000022d9bfa4fb4e1ffc000ccadd0001fc0011087300c826f62669213156ccf082dc70087b8e68ff4c58c826f62669213156ccf082dc70087b8e68ff4c5864f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d730068631f31e13e1c29c739619b2cb58adf73724dd8c6227ab1b8f45c08c5d6934338365ed45c795e4117ddf79f1e5037000000000cf774e2a4bcab3c7e7d2d934cd2977b090fc1e414d26dce53e16cf2cc5971ccd000020cf774e2a4bcab3c7e7d2d934cd2977b090fc1e414d26dce53e16cf2cc5971ccd20e91b3aa22e4f2d8326a68f0400a8ab92d2ec4b4af9beb3abebba5ed8127b8cc0005b156c7020f5322d482e14d95a666d0b36d9b8c100000000009f416929fb4e1ffbc4230001fc0001949300beb0ac49dd993a3841c7f91fc63faf17e32ef6edd1c380a3095e1088aae13a699aa83f4dd1bc0fd9b2334b22379811352d9988876a6e586d975e732930002decf89a99afc7bfddbac08c6c25a028e58f0c7863b7fa6811ff84afcefb933b510b78df6551f844eb2221b0c0bb5300000000cfa6f7b58c78f827c15e8f1b6a5a2a3a92140101719006d8226a363e2c0c8e5c000020cfa6f7b58c78f827c15e8f1b6a5a2a3a92140101719006d8226a363e2c0c8e5c201f44f17b876717517c7d133c9128abf51bb6733c87b0ec7ef06ccb96478e8aec01559cd372f02cbd4b52375512d9d55e153a3a873300000000008a442d76fb4e1ffbc39e0001fc000194dc00fd42c918654ccfaef1b1c70efb20d3f4f6b50b65eb294d05b014930dccd16d4878159584189e77c0b2334b22379811352d9988876a6e586d975e7329308ff05fb385c08528b762683c2ab6864ab1ac031146d9be0df597961625c9538e0bb03ae6a759d66e1717e879ebaad41c00000000cfcddb737317b86698faef84734e9e655fcc2899ee449d13ff70b014419b6c4d000020cfcddb737317b86698faef84734e9e655fcc2899ee449d13ff70b014419b6c4d206716b03191d4b9c5e813998018f03105ad3a5a0a7de1a62efc94339fa84afe9601bf58e573242232de98f1bee4b787f64252361cc000000000003415087cfb4e1ffc00021c240001fc0002fdcc00cba37b8b60880605abd3ca81294ca6b6e725a4038b7f823b0acb2fce829b7434a720075572ce6dd69a1a33fb82e27f0405303a4a4183199a5f2fcab830009a876325699d6979757ac10d6b37eb7f6690a40447f6473779eb9130975998d3a9fd6e9ada19559730bc017843ce1200000000d00a073a9de7c2efe78c712aaea77fa1a6c0ed00b55ed2289cf763763eb32a43000020d00a073a9de7c2efe78c712aaea77fa1a6c0ed00b55ed2289cf763763eb32a4320a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e2e5167565f0e750fbe3b6b7baf519c5dca2be263e6000000000036d63baefb4e1ffc000ccadd000000bae896aae3de540d18e5ea8573182860471082f9bae896aae3de540d18e5ea8573182860471082f964f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d73013dac269908111b8b091edbda123d5884f4d47d21225fa319d344b350762a85c6cdbe21804ef9b2cc53a878c72a001d600000000d0b3fda32eacb51f9bf25e533344e144245d629cb1decc05eef2781a658f4ede000020d0b3fda32eacb51f9bf25e533344e144245d629cb1decc05eef2781a658f4ede205d054509583f78aefb625c44e87477878cad43c597a0f169ff8450a1abcc313e004490108b0958d28e47e691abeb21bddee8d08cef000000000022dcaf58fb4e1ffc000bb3b40001fc000bce2b008f4c05bb6a71e94abccfc1c722494ce77ed0a3418f4c05bb6a71e94abccfc1c722494ce77ed0a3411ec5c66e9789c655ae068d35088b4073345fe0b030031eb004643118075e2e22389b29d78e797ca7dc18edf201a2c324658b261803e8d162b172fb00822da1fe4283f8863a00000000d0c37ae5ff62e92d9f065b453c79bdd8b967a7e7e5e3753e94e0f2929065579a000020d0c37ae5ff62e92d9f065b453c79bdd8b967a7e7e5e3753e94e0f2929065579a203432a97c8b76efce888ae94aab39a57465f1e833f89364e8a4d13bf657c24cfa010dcb7083110afca0bb2af934af50512b0bda0d6600000000008c520f8ffb4e1ffc0006b0b601fc0006b32d01fc00071acb000b5424d01a3096f1a61dded02a329caaed8300d16150352212815041fa5dc70a94c7dfd507f4861975f49a2ef947f1f126a241add5de9e0965d20c483010ac5b643b6dfa29989103ad74641e5fa27626492f08b8337a8415b598ebf2bc6676c73621905a71a15d7bf9f92d6efd00000000d1ce9c61c04501fdade45632d83ba14b76b8cd89de369e7ba9594731e21a8c97000020d1ce9c61c04501fdade45632d83ba14b76b8cd89de369e7ba9594731e21a8c9720df179634db5c8c4cfedca1271ed90c3615ef15757d5c7d6fabbd9e18e8752f5201afe98cb66e8326b286b5eb9dd53b0f3043cbcc21000000000044b7c45dfb4e1ffbf08d0001fc0001195600227ac0c292b7d209dc75272563f6e3e40bcd4b66227ac0c292b7d209dc75272563f6e3e40bcd4b666d4c795644ca86f717628ea27f0af13b0ea70eb7300c49037992160cb8d7f6ad7e13d778fbbfb5d10230b456bb3aca1c044e79fb15c3b1fcef7efac59899eccbd190bdc40e00000000d2148afa283037e255d65a3acc82428d6a712215003963a60c6e015aaaa4bff0000020d2148afa283037e255d65a3acc82428d6a712215003963a60c6e015aaaa4bff0207a296529680d98fe988f25841cefd74be42dc27ca52ef6f46421c200f477525301c1e0f105b18897e33ed0d0636a1841c38e3ea826000000000003140e8ffb2712fc00035e2401fc0003cdd701fc0003ce6400bc0daad062fd3cff45c9494fc80bee6a0ad1ef904e818207ce6a7e9752c006ae4328b26c14af2a955e7e959febf6f6f5e42de569815cc416d06032ea308de1a5d67b291f75e87e20eb4b9fa7246dff5bcf4030ae26c321b1845609d50d04b240cc51862b4a7b3dc9be4aff050f00000000d23a37ad5fc04ff18955da1ea1cec8975fa03c525104f9553b3cacd36045b6ea000020d23a37ad5fc04ff18955da1ea1cec8975fa03c525104f9553b3cacd36045b6ea20347d39a27538a8a7819cb8d3aa5e7484b6ceb2ebb18de76970cbadc12837b98700eaf1ecf2a52c4b15b1f29ae0776532a4fab56025000000000036da7f80fb4e1ffc0006568001fc000ba7e201fc000bd4aa00af19744774b258e0ebf2a01006ee507c6a368f27af19744774b258e0ebf2a01006ee507c6a368f271ec5c66e9789c655ae068d35088b4073345fe0b0308b2ae1b6528eb36f1d87d61e763e5d5d26f6eacbfc6b91305eb30d4d4136e7edaf3bcf2fd07f8a91cdef268465f5085400000000d23e1b9f3cb6ed89beb1f11ac96f61c0011655c6cd02c600c6a671cf92c9f070000020d23e1b9f3cb6ed89beb1f11ac96f61c0011655c6cd02c600c6a671cf92c9f07020a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e5bc7da1882838f4aecbe1de16036780bc6dbb5d48c000000000023a7a5e0fb4e1ffc000ccadd0001fc0010a8eb008496f3b53ff1854c310cec50faaed0a3980374dc8496f3b53ff1854c310cec50faaed0a3980374dc64f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d7309291debc5e6c56a9e1a9b77cb980115c36a4d3d584826e62fc4b6ad7834cfc21e7c80226d46e90f4fda7771b4511152600000000d2467a06e67cfe57ce8723f565c296f97abb663380ce87bb8d5e72989e3301d1000020d2467a06e67cfe57ce8723f565c296f97abb663380ce87bb8d5e72989e3301d120da822286edec580e48efe91cf1129ece56530d16667549522d6bcc6d3e3b09910022de1a923e40b1fd9f13fb4f076b69d9ee94e0b3000000000068ee9c6dfb4e1ffbd50c0001fbd68a006bf6187199e0d3b146d1daeb844abed61dde51215d63ccb848f51351e6623f5841dd00e057e4633722de1a923e40b1fd9f13fb4f076b69d9ee94e0b330145a212f37b991a6c050cfaaad7e83f1347486984174e8f446e59fa6c225691ea679f70613d829f536bb1a311d812cb800000000d304e1e869e1a9aee1952f06bfd8dd43f8a4d12231c5d43641a31f89a53eca2c000020d304e1e869e1a9aee1952f06bfd8dd43f8a4d12231c5d43641a31f89a53eca2c2054be51b0a5708936a13e637645dc0c002a2d79282d4f5f2e89aefdfc4c49c8ac0141307e80a8d668b0bf3cc98a52f8d85ec8cf5ae20000000000904c4214fb4e1ffc0001b6a60001fc0003eb43006f39ee8ed58b56b0fdecdbf64cc71b75041ac7716f39ee8ed58b56b0fdecdbf64cc71b75041ac771c0a84112810ea249524c9060518b76dbee8b86cd3009591bf26ea6f179457440d73ebc70c44310ea56dad7539a93be903e28788cac013b646e3ed4198ca74a8325d8a721c200000000d3a0e645c1830de00ca370761d0db7a75a408b9322ca571fe26b7f8cc5a0ecc4000020d3a0e645c1830de00ca370761d0db7a75a408b9322ca571fe26b7f8cc5a0ecc420c4eca0c58c7f6be21f57ca22938b405aa7b70d1d7670a30ce00d83c145e6a0d300b0adcebc8b989c5d9248b195d5b3a3b1a57a855800000000010000000000000000000000000000000000fbaa690001fbaa69001e88661c273d73b44bbf942d3f1cfc145539969d1e88661c273d73b44bbf942d3f1cfc145539969d05b1290b6787444d5ddfdf30f732ee620dadda063005b7d7aee629c25efc5604104a3a9af1e23663464e0505a057e68cf12317834160597fcf80287a94e98f171a8c79a2a900000000d625ce5bfbadaeae3ea778ba16d871e6b61ec07faea80403dd51a9d28df8deea000020d625ce5bfbadaeae3ea778ba16d871e6b61ec07faea80403dd51a9d28df8deea20862bff54719c5747b08e2b5b646efc0e1ae8527b72e6526554e8b1db8655c5b400c315ac9f0d1a78172378ccf1dbe786b01ee7764b000000000055d1f301fb4e1ffc0010173e0001fc0010176b00b80018523ca775bdcf9f5b35b31aec7974cf3b15b80018523ca775bdcf9f5b35b31aec7974cf3b1517c1532d16104848a1cc23893816c93d5559beac3089b278c3322e9e5193d133bd49d958d05383835371944dca113bae75a3c741a61202a7d3f99447f7521708b308028b1200000000d73cc0f5964b94a5c72bf9457ea1681a4dc61940f75e991492b669697a392ffe000020d73cc0f5964b94a5c72bf9457ea1681a4dc61940f75e991492b669697a392ffe20024f7b3d5ef9e0a82cb75799a1589f8bf5d988e1bc342ac533a5aa94f32fb38401a8b2af0c1699023cd662f648d477e7b52bcdffd3000000000036f40a18fb4e1ffc000bb3b40001fc000bd21b00e433c14f7b979d60aa65bdd41a61793a80cb4af9e433c14f7b979d60aa65bdd41a61793a80cb4af91ec5c66e9789c655ae068d35088b4073345fe0b03008591f0c86bab284e3e43d622ebf60c6f2e508d574fce16bec8cf35a04f69fe667a65072dc7e0ebdc78c0a2f82d5d4a000000000d9b090cfc19caf2e27d512e69c43812a274bdf29c081d0ade4fd272ad56a5f89000120d9b090cfc19caf2e27d512e69c43812a274bdf29c081d0ade4fd272ad56a5f8920593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c0d47eb59e9a49b3794acf272f1bfff17f228291daf00000000002cf06266fb4e1ffc000cf99e0000007334f54da07d3b9e177f6e57c64f97bb0f982caf7334f54da07d3b9e177f6e57c64f97bb0f982cafc69a0bda7daaae481be8def95e5f347a1d00a4b43086108e551691da2642f37b68bcfbc5bbe9984ca51aca15ee24b6fa9b8690ed62c6ed722d091e04ef617cfc99341fd35800017034f0d3853c5351fb8e0ffd3c1daf12c51c2d8901fb8f3001fb05a3da0a60d91a09d34a39ba34e4175d2efca738ebb409e3fbb0546d41a24e83a722000020da0a60d91a09d34a39ba34e4175d2efca738ebb409e3fbb0546d41a24e83a72220a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e57bfc4a68510d0df6c7f9b006df5845a8468b5f390000000000036443095fb4e1ffc000ccadd0001fc0010efea009c14a51ad09e0eedf4d49b11a779aebe5755a4e89c14a51ad09e0eedf4d49b11a779aebe5755a4e864f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d7301099dcddc6560d1039b0edb91bd700e5deae0cba43163fa289a80c2bd22335b5b0e7a1fb8f5494c0e6360e73a12fe0a800000000da21ca075f0b1b6c29df0391165030d85a8d5e7474c6358d9edbd3dd270de78e000020da21ca075f0b1b6c29df0391165030d85a8d5e7474c6358d9edbd3dd270de78e20d77e2ba2a4cd96a0cffe43117209beaa0bcca463d583c02ecd118a3e04e5ddfb007caf7956015e9404896b6492227b8517c679a02d000000000036b807b8fb4e1ffc0006567a01fc0006c05c01fc000bdc0b00f5a25e1acba9dae504fb92b2b7f4f8c776b450b8f5a25e1acba9dae504fb92b2b7f4f8c776b450b81ec5c66e9789c655ae068d35088b4073345fe0b0309760a3bdbe28cbc5c64b7426b7b59aa84f6ad6c4fdbe040a9158c359e39feeae4b4168d6231d636eb4024f072b4d465500000000db3158d303d9634fc0a4772452707e4f6154aabedcce40d60e7932137ca52efa000020db3158d303d9634fc0a4772452707e4f6154aabedcce40d60e7932137ca52efa208e8e515f7025352e7c608479e413beacf0d95cbb964b47e4a98fd27b6b6b628a19379812a735584751c27ae8d47205e7048ad8afb7000000000034d41347fb65b0fc0005e6990001fc0006584400f312f66e9433c75b461b481f0576d3acd398c223f312f66e9433c75b461b481f0576d3acd398c223379812a735584751c27ae8d47205e7048ad8afb730989f584df6e5a359bc469a4975baccda2bc6a3fc3e89721c639f5567db7abef79f31ddeb4832b95418d49322419d3eb000000000dbe6cc582f7b5c0eeeab18c03d651274a36a26e5222e9e6ab5dbeef9590c3d40000020dbe6cc582f7b5c0eeeab18c03d651274a36a26e5222e9e6ab5dbeef9590c3d4020a94e29c854f2cf4113be2e8b61faa8bc4749778dffa3edefc112d01de9a677a701bbac279c1e96b87d49a7da69df88948d81d5043c000000000023a39c47fb4e1ffc000b9ba201fc000ba67d01fc000bd4aa0099b35d5698744965f753a627926c0d59b1821c5199b35d5698744965f753a627926c0d59b1821c511ec5c66e9789c655ae068d35088b4073345fe0b030811536feb53c015c2aa7e518611a2f6609fe3362d64b225dd26ec2becf55100402e561aff014fa31ee0ab41e53d437ff00000000dc1a51970c343e17706bf77aa4309149613f7a69650f274b6a9fa1c6dd1c4f87000020dc1a51970c343e17706bf77aa4309149613f7a69650f274b6a9fa1c6dd1c4f87205b016215386c035a42042a93736befccdb87c30cb90adc3b1279da58ac57cc1407eeccb10d4e73ed1650cd3fcb2dd3cf4c2f7347420000000000235adf83fb4e1ffc000cf8b101fc000cf98d01fc000cf9fb00f49a8758b606e7ecf90fda27c30efdd71ab8be9ef49a8758b606e7ecf90fda27c30efdd71ab8be9ec69a0bda7daaae481be8def95e5f347a1d00a4b430846e41a6e970b78fdcf39e3348689944de461e961a0c5dae123c3b7c4d985bbfb0eae2da56b6600dcf82f196df258ee600000000dc2e02ac95ce4ccc9843c38de7bdaf32f2a1d5966c054127a3f4ca4f4bbd5991000020dc2e02ac95ce4ccc9843c38de7bdaf32f2a1d5966c054127a3f4ca4f4bbd599120a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e2239379b568d6e941d8e551204c4a13b38a8313155000000000023576903fb4e1ffc000ccadd00000032eb51df8032392d44594907e5032d23df570b2d32eb51df8032392d44594907e5032d23df570b2d64f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d7300db85a27cd589d225beff9977aa0ac32551d15bd906a899bc1ef33458d7c979118f92bf1de4ddb55144acc2f7cf6d85400000000dcbcf8311e414aaafac3650f3f61326dce386eee3d1a53da86e4c9925af48d9d000020dcbcf8311e414aaafac3650f3f61326dce386eee3d1a53da86e4c9925af48d9d209d8df45a92c9e486da531a3dee6e38ce6d32613f0f65c3faaa4a411e31f8bcdc01c939bc570a54556243cc0386615fd4f77fc3a3950000000000b23e440afb4e1ffb66900001fc0001193400d930d39369c43d62ef0fa29c85a349673712f597d930d39369c43d62ef0fa29c85a349673712f597c939bc570a54556243cc0386615fd4f77fc3a3953089277d2620e48dcf8456cc8815aa18ad3587bbf40cf0d1718696bd126e19791bb600b22f1063d4e5e8efe85fab8f90c800000000ddb33a8e1dc94f0d2c78faf99f2209c5a6304924675ee639b237e00051e5adbd000020ddb33a8e1dc94f0d2c78faf99f2209c5a6304924675ee639b237e00051e5adbd20a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e020173018c4450e8125fd37bc507fb4feeeec09d49000000000022de527ffb4e1ffc000ccadd00000017a7876ff09a4592bf27959546c02232a48d49f117a7876ff09a4592bf27959546c02232a48d49f164f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d730882aed1df01917097a5502ff541a800d268967ab39c8f841ed62c5387eb46459d6f6959166cafec148dcae03830e83a500000000deaaf275e9e384f3e7b190cb4e779d200a8c22dd968e6eaee0bf0a2900ac93b7000020deaaf275e9e384f3e7b190cb4e779d200a8c22dd968e6eaee0bf0a2900ac93b720a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e080dbf942f2afe5fc96072af6ae4599720d1e88c3f000000000022db21e7fb4e1ffc000ccadd00000076c44d67639aaa8fb877f1db08d5e582b570c25d76c44d67639aaa8fb877f1db08d5e582b570c25d64f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d73017f78abcee6d2ed68bf2c82afbf56ef9af67313e2eb655ea5178850907cb3057cae0bb5a1d09f161057bf62f9d4890c600000000df770657631b27b71aa97f295c8c345df6f73617f2cc48f5d414955094a4d2ab000020df770657631b27b71aa97f295c8c345df6f73617f2cc48f5d414955094a4d2ab20eb25924c31ced9ab50bb1efa43f51e7f9e3a883b0668b1aca170731b2c73876f0116464c645e265c1dc215d0da895a91cf33c53f720000000000a123e12efb4e1ffc0006b45c0001fc0006b4cb0069c4cac4ececac7282dac6b8a9198772ce3f72995603402752878f5c76e9f40a3091b748a731beea16464c645e265c1dc215d0da895a91cf33c53f7230865e0561715f28e996d2c63e1ed462c82d403ad9300369529cc8932f02a8ecd6bf5c5b316130997f2c1ad1df700ea2fb00000000dfab7fd7e6f141d1ad7ff9fcaf8dafaf85b05dafc9058b376a33c6f4ee1da607000020dfab7fd7e6f141d1ad7ff9fcaf8dafaf85b05dafc9058b376a33c6f4ee1da6072032048e6d7e2751d4029bfddd77d06ea72c07fffb2d2a67b73ac1cc499fd10cf90210837fd9d5cba10bb91fc24c4faa5c7f591f4289000000000091efeb12fb4e1ffc000153490001fc0002427c004c90d0d2b49179ba1311496241623928b4e9bfc64c90d0d2b49179ba1311496241623928b4e9bfc62588a17ab3f917f19afeb8c32fa7c486ab4105a3300b4282cdfe1cd639e60b6c58b2f210bfe6b57f8f247cc5b55673d188ef458270c7314f7128b286a3326b9ab6109bd2ff00000000e0e5e51a1d6c471289fa4dde52bf5de747e1238a478a7fad107427a485921dea000020e0e5e51a1d6c471289fa4dde52bf5de747e1238a478a7fad107427a485921dea20c476e128117f5b8573cdedca3abdad1e49bc2d1ccbc8d536286a10c14c4bfbe9012aff26638de9d67c2ff76983669a27a5369f1146000000000002030405fb4e1ffc000834c30001fc000834e3003a8be94ab784cc8472ac6739fc763589673af28152b3089828ccd5c5e2929bb45057829bf2cd9900194748ff7e003ab02fd6964087130588b6c71c743019224c48bde28c061c99ca2a641ed1f695546fb6f1d103e93b4d8aa5164f5fdced8073ee239baa885cf377c8c173016500000000e0ef260e49c9f2139825cc98504c536397595e05813cc1de5dff2eb793aeb5ef000020e0ef260e49c9f2139825cc98504c536397595e05813cc1de5dff2eb793aeb5ef20aaa6c559704660301f5d58d95bba0be1df90ac849a60e537a7e1895e3a90d354016582f71a9a070fc634378449053280e8b5a64a0200000000008e5da342fb4e1ffb92e801fb93eb01fb96fa005d3a8bd28dc7d0ea750f976b89991482da5ef8bf5d3a8bd28dc7d0ea750f976b89991482da5ef8bf8e9c7503df018ff14c7f28047d833d1dda31efe5300dda9adbc22cdf89c04e8ee714da7d80dd5620c1d14e30780668d3b782b2f0acac9f00a556be1548733c1ad1abdd96ff00000000e1051e900f3f13c6cf79e1734ae1c65683c627982c5ddeb30f8afaa85116ab4e000020e1051e900f3f13c6cf79e1734ae1c65683c627982c5ddeb30f8afaa85116ab4e204dea6406996a98efea88a66bddbe7f9568093185b08c865b1b664ae0e594c7be06aec4b5523c900755019a250cd5922349690a448c00000000010000000000000000000000000000000000fc000cf6350001fc000cf889002a5b7ea1a484ccab3250dc7656ca99f7bc1cd21c2a5b7ea1a484ccab3250dc7656ca99f7bc1cd21cc69a0bda7daaae481be8def95e5f347a1d00a4b43000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e11bc5514ce9e362112fe4bc2356d68a63dd62b3834e320726709bb707564510000020e11bc5514ce9e362112fe4bc2356d68a63dd62b3834e320726709bb70756451020a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e499644ab02bf96193c58f4421e41886319036b09c60000000000235a35b4fb4e1ffc000ccadd00000002b43db3b33d56022be0be0abcd8a470f3624c8602b43db3b33d56022be0be0abcd8a470f3624c8664f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d73017596d7a72b65531fffd5f610752422d6e286c975f30d026092f7900f8015073bd6f6d1b85dd3981814c093910e7dac600000000e220b3b30879a4e489a99f265f00aeafaab0fbedd0ec3fa194befc03fe93ac30000020e220b3b30879a4e489a99f265f00aeafaab0fbedd0ec3fa194befc03fe93ac302049104fbd6215a0f0642bb38f73f479a8694ab35111093a57d07464b7224857e70060494598e236442ea115c2fd4772c8ef4881c0c00000000000951c7f08fb5207fc0004f3ab0001fc0004f3eb0027ac0bbb97d398cc78587b58ea40d92039f6a27527ac0bbb97d398cc78587b58ea40d92039f6a2754a0ba964dc2701ea622ef904633191f9444a5fce30127147f0cd5bc3ec7c8c5704924e855d46dac21de72e2de112f7dee7c9c3f9c40d4474c0d9ae36a56b800659af62c16d00000000e341b4207f799d7b216593303c5705c97825331805f32cf54188dd05a7e9940a000020e341b4207f799d7b216593303c5705c97825331805f32cf54188dd05a7e9940a20ed0a3741f44d013b11c389c282f6ba4b53abd15f4b8b7d2b08ac06ccb7a923f401844e2264660076d8db9477d915f43ee0c68d228c0000000000369d0891fb4e1ffc000384570001fc00044423000ee3064c60e85c3f9e8175b2a4d748a2fa3138949dbb34ad2ac21a13371e4212a67150bbc0320b2ff28f590dc3a245b02f545deca4b8d37217444def30029d0298b3ab58f541f566ba5ddd40e8e1e711dca26b1757fd1b707baea16ce77aaf8a836232809a5e1d301a36f2045800000000e44e528f46f8338398e514570b715cb77f2e001bed967bf0012f99a81be34d9b000020e44e528f46f8338398e514570b715cb77f2e001bed967bf0012f99a81be34d9b20cbfd47c5be15b98099bde2b2d79a1b71ab29e9f70fe74b9a41d3ad87bd1b33f900a51180fa46b6e0e6763d1ec58803d676fddd4a3f0000000000235590e7fb4e1ffc000bb3b40001fc000bcba300c830435c4611335accf4d70344a9512e4af1cf82c830435c4611335accf4d70344a9512e4af1cf821ec5c66e9789c655ae068d35088b4073345fe0b0300c07de8f27328b0e1dfd46c77a183f153ef4179971b08597e3206b97b7ebd80a6d0fd81ae6d69fd9f1c2425952e6636f00000000e461d74c2d6f83e032068bf1f8bc5e019f220187c74ce90625ffff2fb0622a48000020e461d74c2d6f83e032068bf1f8bc5e019f220187c74ce90625ffff2fb0622a48204d5e955db2aa6907ad086e36d6e596554d9fe90df258edb34c1db83dbe05bded00c82b198d97a2b96efc25645a104f3de3f25ae4dd000000000036c81bcefb4e1ffc000bb3b40001fc000bcbaa0095745dc68d45784cfcba71fd18c5b0b0e2ed4f7e95745dc68d45784cfcba71fd18c5b0b0e2ed4f7e1ec5c66e9789c655ae068d35088b4073345fe0b03092110df65b98e79912f6b80aed1eda6e66c55da2549472aa7a089a003efdd5244b39c208acf902198701f623fac145b300000000e52d2f726c9d7fe66a042564fcde9d4189180b7f9debb60ae3241872338b8e9f000020e52d2f726c9d7fe66a042564fcde9d4189180b7f9debb60ae3241872338b8e9f2091cd1bffaa50fef228069e113b7935af4b78c904a32ed0e7984b1086478373020199f5f489bbf74630e2aa67714aa7596510133be5000000000036cad177fb4e1ffc000bb3b40001fc000bd21b009017184ce5f2e988321891515465de3330af413c9017184ce5f2e988321891515465de3330af413c1ec5c66e9789c655ae068d35088b4073345fe0b03010487fb44636ebee88be5e76841d80b2710c25717d82d4ded913ca5c9c9a5d85f80268687b237632cac812518a2464cb00000000e558c21609f13196f38a0e135c8a56ee4632ea1681a9dedd5d65ae8031b34be1000020e558c21609f13196f38a0e135c8a56ee4632ea1681a9dedd5d65ae8031b34be1208e8e515f7025352e7c608479e413beacf0d95cbb964b47e4a98fd27b6b6b628a07082bf9bc77c34eaaf9c9cf4b1b8cd01f1768bab0000000000034d41347fb6596fc0005e6990001fc0006579c0018fdd71cb9d2d0a4cd75e08191dff37fbdf4465018fdd71cb9d2d0a4cd75e08191dff37fbdf44650082bf9bc77c34eaaf9c9cf4b1b8cd01f1768bab030005d1f334fabccd08847756effff3116eece973c077e3acd1aa936f4e51293fa8753de661dc7a03edde24714eb7acdcd00000000e58b99ba67999559acc105b139ad7c0f75e4b88b64ec8e9e3f91d19b18a02fa5000020e58b99ba67999559acc105b139ad7c0f75e4b88b64ec8e9e3f91d19b18a02fa520b4863351e597af3a020f3a1bdcfcca49c63059d3a2769c3bc5628f2c580d988d006156c9f4174e1544f07c378dc4c20b5fff8877ee000000000022ddabc6fb4e1ffc000bb3b40001fc000bc78300b42b27cc27998975c7ebebbbcc18c98c097b60aab42b27cc27998975c7ebebbbcc18c98c097b60aa1ec5c66e9789c655ae068d35088b4073345fe0b030067ff22ce46ff515d5869ef672ace862c7afe2e81a6820d39098419322ad2858a3305f03601a9a85f76333be38b65c4300000000e6595f88f935fef934a6d51dc0a1fd43e65de1adfacc2c99851a69d80cd26493000020e6595f88f935fef934a6d51dc0a1fd43e65de1adfacc2c99851a69d80cd26493208e8e515f7025352e7c608479e413beacf0d95cbb964b47e4a98fd27b6b6b628a3273c764874df7a0f6d7b1c77ae924dde0e3affe430000000000369ad3f2fb65d8fc0005e6990001fc0006575400ca9f4452a8988619c535d28f0b25aaf2c34b5d13ca9f4452a8988619c535d28f0b25aaf2c34b5d1373c764874df7a0f6d7b1c77ae924dde0e3affe43308f72e69ac2373a62f14b7b1d99fb24eafdc87b74247af42a591aef0989c9a3e152197736dbc266b2535c4b4b53d8ec4a00000000e780a06795b6c316aa84451acf07e0f11f9565e256a59057717fbcf0008ac254000020e780a06795b6c316aa84451acf07e0f11f9565e256a59057717fbcf0008ac25420e06631f4da3659b5efefa7eda26e82d9f30427da7c63c0943aa4e6a5a03079c900d1f5e6e6661ec2fbbd62e961da89d2d9fcf11099000000000022dc5846fb4e1ffc0006567a01fc0006c42101fc000bd4a3007d1c61a5a5d33cf6b75aad99d80d90e6f6585dfb7d1c61a5a5d33cf6b75aad99d80d90e6f6585dfb1ec5c66e9789c655ae068d35088b4073345fe0b03007f707431f05ae863a756854d6a8e6c5c37d071f5dc9e3debd2057c36106eaf8102b3313d1b369f3dfddefbc1394639400000000e9126eafb8f62f5a4e8b4d4f2419f4377a8dd14635fc749f9ca2636ffa93815e000020e9126eafb8f62f5a4e8b4d4f2419f4377a8dd14635fc749f9ca2636ffa93815e20cea979a463cdaf780c42b7a196049c04fb8466bf35b0618814e0759fb702c3cd01e0ce79910a4636b0e6a1d9695cee5aada92ee76e00000000003695cfc1fb4e1ffb699601fb868d01fc0001194c00b2ea896299dd86bc7c3353a40d354be43ca26372b2ea896299dd86bc7c3353a40d354be43ca263727eb0a0af302dd9ff95daf9e98d2f1f2c5d764f74308ad9500ef26ae510e0dd8cf0568b2a89d1234697873db2fcdd11674a73caba91cd416f9ac701f4f7807d8db102bc4a3900000000e995e4b4ba9fb3fc8cbc7c779b8b933367c54166175c3cf507aa92d0667ba7b3000020e995e4b4ba9fb3fc8cbc7c779b8b933367c54166175c3cf507aa92d0667ba7b320a5fa769a80bb95a3901423e38b27a4708f7ea2719b1e4bd01aa4a5b8ec9eadb300d33fa6c54b097be5bdc537d894e2d2f144f9847b0000000000ae22e96ffb4e1ffc000cf03e01fc000cf17501fc000cf6e30007f79cc14feaf70775dfd89cdaabc42f9d5a3416ce7f101b7f075273c892063b1b8571311737a5767f95c0f808aff27883260bfaf9cfe2b84519a6b2300620124f5dbe95b93bbcbab48452ba0cc47beaaf554e63db5deef90c10ca79c1e83c08a43d4316105419bccf6595802300000000eaaf0220c44e4e049b5899f162e7adf2da1e7946a2272489f304fe3df5247349000020eaaf0220c44e4e049b5899f162e7adf2da1e7946a2272489f304fe3df52473492050f57d34e7aceac2e5ac132c091ae69842d484ab382d59ac5459a9c8c3efdd4b01fac33d28f64870ce06e55c632d3ce829c9aa8e4e00000000009fcb2263fb4e1ffb641e0001fb64420016c792ef93229ad52721ad5b08249eac743fb74f16c792ef93229ad52721ad5b08249eac743fb74ffac33d28f64870ce06e55c632d3ce829c9aa8e4e300452f32ac367f352d6ef53f984667db9ad658bf940292eae2440024e5af9445f7a7a618d536c4743c9de4c3e07b6a5f900000000ead18f6dabac93c3fa0df238e992fabbecfd75b28dfbbcbcd0ac4bd4dc89a255000020ead18f6dabac93c3fa0df238e992fabbecfd75b28dfbbcbcd0ac4bd4dc89a25520ae5c3b488065fb736209d417e87458b953d6ac9b7bee596447ac119f68f3a287008ff714a271165a679a084036555ef7ea685a458a000000000022d743e0fb4e1ffc0006567a01fc00068cf701fc000bd99b00c9adf3d64cbd87212f093e52caace7296c89fe68c9adf3d64cbd87212f093e52caace7296c89fe681ec5c66e9789c655ae068d35088b4073345fe0b030023bdd31086c9f2de87f380a0c24fd3e7d699a2a43f87bc8d5a395c0eb3f8e19d82af15542302c129c981f352a3e890900000000ec6e4e052c3b28d77c13ccc5072b5f5c185e1a53a6ffaedbb1de9739c0d31489000020ec6e4e052c3b28d77c13ccc5072b5f5c185e1a53a6ffaedbb1de9739c0d31489206fe7864bc5e0241a306eb3adac70d56ba305b520ed44b6917981be5862ac7c76011172bfbafd8ddfbb947170ff69ebc2bc1a7c16680000000000c380664bfb4e1ffc0004bc490001fc0004be7b00cebc041331aa21d5fdce3e44b4a2a520889d4ba4cebc041331aa21d5fdce3e44b4a2a520889d4ba4382477245731a85b4a1b2ca6af9e904517d07e97301926b68942b544b4e17347c5e0d28ba91453984294c7679965f3a1d3cdcd9f5bf80f2c28a48b503f301bada54479896800000000ed1caa0e3a8c97dffb71fd26d6aa03a4d52347d8da71709220b0b4357e2a7236000020ed1caa0e3a8c97dffb71fd26d6aa03a4d52347d8da71709220b0b4357e2a7236207027e327b827fa7edc0fbd17b85900f2787d210c76a3ea06182088249d157679008e7e021f47d1e9425609af4dd695253fd8a9a0760000000000235a0070fb4e1ffc000bb3b40001fc000bce430039e05a296f11c657770a6161ea00a72b625d1de439e05a296f11c657770a6161ea00a72b625d1de41ec5c66e9789c655ae068d35088b4073345fe0b0300583a5fb61d625bb0640bbd1dbec505e8747dee734bd9dcda0c62fffeb13e24bc8cf3475e1535f8f8700fc48f177569100000000ed8575335b7e0b420b09b4b8c530711b98aa472504d91bbca9745873a106cb0c000020ed8575335b7e0b420b09b4b8c530711b98aa472504d91bbca9745873a106cb0c2092ebd7ca076b40f4012ca7e115e04bc2b1baab1be5289f8c975d580d64848769019aa6ac346d95f15724c602b262b8178333646dcd00000000008b3b51aafb4e1ffc0001aaae0001fc0001aae4009f9695e95af100e56314bd08680812a0f6256e119f9695e95af100e56314bd08680812a0f6256e119aa6ac346d95f15724c602b262b8178333646dcd308dd3b8d006c8ea260bc6158daf0680c5cc7cf4936458024b51ea2036a800ec6563d75135004055d94743b8341b70135800000000edc1fe5456b869747a4f41f92ab8bb8b10c1f43bbbd97957a16698783baa0d2a000020edc1fe5456b869747a4f41f92ab8bb8b10c1f43bbbd97957a16698783baa0d2a20a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e335e9d6b2065deb3d586152f44f0578cb0d51a5e74000000000022dc9b03fb4e1ffc000ccadd0000000e42f45a86824089891f17af573e84512f00d8850e42f45a86824089891f17af573e84512f00d88564f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d73006e81b2ac08c3ba6308868ced5075f366013ee8598961bc84150d8dfe9085fdceafc082fd18d3a7bb1338b74584048fc00000000edfb29497dd86e1bcbe72cce1cca1adbc1d9a991d3384c0a1a83d35808cbf5a4000020edfb29497dd86e1bcbe72cce1cca1adbc1d9a991d3384c0a1a83d35808cbf5a4206deb6528ee95044163f5e417053b8b43f32ebf26fad8d9e47e1222d611f7cd1c00ff84a8ead83fb486d9321ea63b356b287c2c569600000000000b7a212dfb4e1ffc000607a70001fc000608330035d72ae28122e666401fbc5f914da502815aedd335d72ae28122e666401fbc5f914da502815aedd3ff84a8ead83fb486d9321ea63b356b287c2c5696308d052595c653122cccb964230a5404399634e7cc6b3fa9314b54678c28d2f9c4854baa7be02845937bb0de35e43cfbd400000000ee12a4658170bf28f8ae6eacbc48fbe62d009582bafe6714f630484b14474944000020ee12a4658170bf28f8ae6eacbc48fbe62d009582bafe6714f630484b14474944206d945b3976197533a8283ecf24a1f1b86c51eaaaa28b4556e6fac59a0d21875f0108bd9dfcf61ed79b051ac428f69328463aab0001000000000034ce62c4fb4e1ffc000a4a8e0001fc000a4a9b0025a3f54d7d674aa11d94a1a7d4f40d618f8aff3a9a870b5d4ccfe0068e92a6cb4cd35915ef94df9c3a840c9fab8a7618147fb2f3060fd847cf86f08f30121a1cade221b1eadcc0c7a02a03508551dfb97b959ae1511d4cae47b503b39ba0fb37b984e4010164378513edfaf07200000000ee733db5519c987496eb3b871d5fa543ddb19db3e848f2fbb0af01585fc76af5000120ee733db5519c987496eb3b871d5fa543ddb19db3e848f2fbb0af01585fc76af520f56ac75f5801afb0fbf248e8b39db1dd43a55f1d873beb9674989c51b53d73ee0191be18196047ed60fca300e6fdca0b7bea81beac00000000000238d45dfb4e1ffc000de7c001fc000de9f801fc000f13a3000bf9547a7b4d12def0019da71e989821a60d9c915b44dc4b3f0ed26a8243afa46bada49c18da6b2a21eca01872dbfce4bf20886a004f6caaa69c1ff730b695a4757d60c472f67a7807def81ab7a52dec3bc64aa1c4188d02a4768ac3a862b404f0656ed395f1eb6470dca7bca400018355913e3791438c18b5ac50fe03784df789424101fb8f3001fb05a3eeb8cb773673c77f664501bc68b813206e9cd0920a11cb74cc918897804bee24000020eeb8cb773673c77f664501bc68b813206e9cd0920a11cb74cc918897804bee2420ded1303c7551bf04f34b3b61a00d142d46f2329ed8137295b51c89f613f5b62f01df33af9d739271f406b1c31d11a2f570c524e9dd0000000000030d2293fb2711fc0003abff0001fc0003b6940087de47ade017f67b717616f8bd4f5fc3005dbe8587de47ade017f67b717616f8bd4f5fc3005dbe8567918cbbd6928be3a8e76c1a8d89717c2e3d08ce3004cab5bc1d73f5f8299feeecc0bee2d76f27c3b2a56a7e2fc1f927e495ac9b2a0560b7d82fd06fa8fce4af69d0fcb10b00000000efb3f539ad844bf34f9529602480e504885915b42b10102b9be38c4db31eb1b1000020efb3f539ad844bf34f9529602480e504885915b42b10102b9be38c4db31eb1b1200ce06bc2b322337c43a1d3befe252ff366f81600bee06a14c07ac462e17498e00020eba3616392708db9c3a971924380b6080bd17e000000000022db5eb2fb4e1ffc0006568001fc000b9be201fc000bd4aa0086cd7c93e15658bbce6b175c320e67aad70c8cc686cd7c93e15658bbce6b175c320e67aad70c8cc61ec5c66e9789c655ae068d35088b4073345fe0b0300abc2b9eab7faedd46b321ef733583d1edf73112492b5a84f8d61bb83801f1269878d663ba0f037752792ff5226b02b700000000efd6717fe659d2b949955f2c01985d4ff36848c96e425c6bea4780e2ab0ff2d9000020efd6717fe659d2b949955f2c01985d4ff36848c96e425c6bea4780e2ab0ff2d920c8c64c21433a191413a465619ed9255bec0027a8f938e34af2846a3ef764d87101719ad3711be4ac4c4d3e916a78bf59fa8b486d1e000000000022e0950afb4e1ffc000bdcae0001fc000bdccc00e88bf8b114ce7d91ae8968eaba14be60d05491579d39d1cb8cd5844cb453cdb1a62b73e0ea6cde7b43e505b33b6e189d0f3c9f598a1e551fcd953cd6301560ff0ddb3c1e8bad9f2e237b3ad39c37ba804fc09d4ccd928362ee874308b29e827ea60c21b3c04787d771a16e732100000000f0e0387783674bd818ebae2fb6b5c20659cfcd5c68a2f8a1f03b03ae3004724c000020f0e0387783674bd818ebae2fb6b5c20659cfcd5c68a2f8a1f03b03ae3004724c2049106aa9cb4165261f6af3c21680cc16effd3449f9f73ac5e765c2e2380587ee01e02dac43c4d57aa2a821a9b0b25068f5f5edfa3200000000002be54d2efb4e1ffc0009c59901fc000c0e8a01fc000c13aa00e53909416dd7f61cdabae76c20347cabeec8a21ca6986dc7a8d22b1ec6edc799608163d63eb92ff6e02dac43c4d57aa2a821a9b0b25068f5f5edfa323088aef910c408df03f396e0f92411de096d08d4ea727fb3abf45541685d0327ee1e8d5b5a5057c92fa2360d9c0abbd11f00000000f129a2035414a54881224bb0926390bef90b8bfcc63fd2757ae95f07fc9cb381000020f129a2035414a54881224bb0926390bef90b8bfcc63fd2757ae95f07fc9cb381202d618978b20c66d63c97dbcc2f064fccbc03d2403baae27322c43315b1543391017f5372f19a541e9afb85c443c3645ad95a37f15d0000000000a747dfd4fb4e1ffc00023d3b0001fc000242030026cfdbcfd54646d88cd9fe62da04f5e70eba5ce6e21d3baa7509a95b0a9d741549047c2e90ed8aa785512acdbe7b71cba4d29a25df44193d6e950c063084657bff1dbf81b2aa50e385d01549f9c3683994ab0b16d5b7e3ede8efe95992bb621ec221c5003d2f9f26fa190ffb2a00000000f14c9af014af86568a4ae2582c3ffcf6602920ee4155b8a08b1054cbf31536c1000020f14c9af014af86568a4ae2582c3ffcf6602920ee4155b8a08b1054cbf31536c120a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e6df28cf902610e816bd509758353005ba3ee418fa0000000000023593580fb4e1ffc000ccadd0000001cffef89d1917166a4e3d2443411f6cd1032bf291cffef89d1917166a4e3d2443411f6cd1032bf2964f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d7300ea46d70601eb45319ab495e2462f981debc8316df2bb1a679ae3525c7f517e535b69a02052844374c887a9312a4798400000000f2382c75e2009f5ce32df63933aa700a05239dde4f2df94a40ba2234b8e777f2000020f2382c75e2009f5ce32df63933aa700a05239dde4f2df94a40ba2234b8e777f2200c69789a95af40ef45beaa00faff26487428af61cefe1f64b4099f4a90583bbc015d58fd558edd7f6e2ed85b5fa134648f477d32f30000000000342ad593fb4e1ffb783b01fb868c01fc0001196300c3bd25702c4c5cabd642d5498f118ec73134c534c3bd25702c4c5cabd642d5498f118ec73134c5347eb0a0af302dd9ff95daf9e98d2f1f2c5d764f743016d49c42cf506d5687c4035fc8ea37c2bc293761412b8c28a73f674df9d3983581f53a8eeb7f1c7b6382bb0485df381400000000f2b2cda32fe9ab9a29ad463e878bc4061e3fd74bd30508c53a214333f8b58839000020f2b2cda32fe9ab9a29ad463e878bc4061e3fd74bd30508c53a214333f8b58839203988b5f83343213ac50805d34bd73f1e06c48b873e46ad299aabe92fa3cdb2f201e0e440d4c365236c93f5fbe402336cba2c5a506242c800000022d1d386fb4e1ffbed4e0001fbf1ea003e58db4338161895653ffe307a9fd3567d7b3c3bba7c694196934a70e11ed92a56db5766131968cc365b70e557479d57b35b99598327dfbd0bf9291330195b44e1d553d160abfcf70b8ccfaf24480ad34fa7917fb87675f712f0795a23dd0107f5f3e39c07474697e95b15170d00000000f311a4630250c2c2fe0f6121d7214b1e962d2e7385e78cdc3ff694c9cfc0cbe8000020f311a4630250c2c2fe0f6121d7214b1e962d2e7385e78cdc3ff694c9cfc0cbe82090d0e59ebc9e022b3074f6eb4a31650a7d41f7e2d4a97a1956577ab903a5afe801794b99b1cd0a4f69ee1072b041560edd584e1d1a41a00000006a334e46fb4e1efc0003a9ef0001fc0003aaf4006171861fc24ad0c91cf01b5950b00dfd2b0e65e757f73d89afcfbd3c34ff42e19f32af77dfd7a8990fdbf7aed02a6e0d546fa6c8abb8d7e1f65743d03001841a16adc73f0224e6544d0cc57057ee2508c906706307ef8561908bd476594ff1e825798faac54c8f8a66583a3dba00000000f39722e1e9d02ddb49512b16674868a865bae2a912401bb6b006b09a74186beb000020f39722e1e9d02ddb49512b16674868a865bae2a912401bb6b006b09a74186beb2047d6aaf3ee8ba77263837e9720492e7b57d59345881f5443442861f43fbd0f68017583afdc80db725044af4e20f5a892f4a60770fb0000000000030d2293fb2717fc0003ab450001fc0003b66300bc97efd5f5716cff0af50478f0d383052635c7ebbc97efd5f5716cff0af50478f0d383052635c7eb0740696a1602a31eda2d6bbd49303ad3c665a3c63096395d8ca159e5ca66eae7685beb6766a6c0ae50b4569809c4ecca3e101a1f210bc35637473b5afd5e71bfbbc976277d00000000f3eeb1461780dc6c62c5793df607e23f55153945b17ee029b3404dce7450ca84000020f3eeb1461780dc6c62c5793df607e23f55153945b17ee029b3404dce7450ca8420a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e6aee197c209560b451adf796ae802f30ef1375183a000000000022ddc467fb4e1ffc000ccadd0001fc0010dcca003ecf5e66d9c0373f20f86d3fefdce2165c19c7be3ecf5e66d9c0373f20f86d3fefdce2165c19c7be64f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d73090051db915bd86bd938746c14440b11ee3b2801cbc6d6c1c912e8b41ea5eb1d8f852abf220ae91ecdb6da094846c1ba800000000f5e25c2dc6aedeff586b26a5fef15bfeb332963bd32fa02d1e8e1b0b74784c7e000020f5e25c2dc6aedeff586b26a5fef15bfeb332963bd32fa02d1e8e1b0b74784c7e207d6e5caedcfca225cb8da762d52bcd3d73b2b3ce2c7f8fa3f900bf0b6c75460b01c106d71f6a7402065c35fda833c7148623179b56000000000022cb31a3fb4e1ffc000a4aaf0001fc000a4afb0015b1012a3f35f6b6873a144ed87b5711f467030601878fc5b0bde020f35fd7dab0709c0faacba8fe3a840c9fab8a7618147fb2f3060fd847cf86f08f3099cec23c58cf89081e39d8862912ecd50a18b44dbe92af0378ef2a3bbbdf4a6a11a76af5b70db205cfd31323391ee64000000000f5ff9fbf1daf5db3539c7e307d9d50b12bb58a491b2f684c123256fd8193aa22000020f5ff9fbf1daf5db3539c7e307d9d50b12bb58a491b2f684c123256fd8193aa2220693022de7fb65f12cc990c6c3db7b02488cfa0d222ad3ce8ce8970dcd945666e01feac00c4a5ee38b2a8e6857126d5b39c05062c1e00000000010000000000000000000000000000000000fc0001923901fc0001ba5b01fc00021efd00d3f5c934320be62f66647087ee07d9e3b68996165bd941a8832f305921d4f2bdf7946d8ac1b6b379bcfd75be0403b27a8121583a01d004c114f919753000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f60f6c91316fb671bc4887c714f9ff99a836645e69d0a411fd85468602489133000020f60f6c91316fb671bc4887c714f9ff99a836645e69d0a411fd85468602489133200f90ec21220fcd572f8a7361d9b45930be3067834acbb21df32da4f8070d03c701989c8077698d0a9dd2f90be13019eae3a8d13e0600000000002cea7d97fb4e1ffc000b18330001fc000b1a2b00e3ea58a452a6c8d408df64a2f8511642921268034e28cb55a991fc1d6062edd80b6597f7e72d2a922567856cdf62ed7325c44bd7b7557e1acb330a633006af52990c96c3d5aa6d8d29ffc118f43a74c12f3dc860825818e70bbdc9548a6b62d680af91772ba9231378cb6d292500000000f6496d3c0ac1ad94ff5e3aab2edcabc1c8ba3fbfea0ef3026e90ba7863990381000120f6496d3c0ac1ad94ff5e3aab2edcabc1c8ba3fbfea0ef3026e90ba786399038120593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c050d1611e03249023d89c1ac086036cbea392768cc0000000000340dfab6fb4e1ffc000cf99e0000006cc3fca46aae1c44ea1bab81d506e9f0a3ae1d056cc3fca46aae1c44ea1bab81d506e9f0a3ae1d05c69a0bda7daaae481be8def95e5f347a1d00a4b4308f2df81ba65db70eaab625c5fe46f0f5e52a45b25c761686db23b4f18e547cb0d161912dd187302eb6f7c4a9a666a3230001fe2d4798df3e9b41a6823bc0b3f020478e87925d01fb8f3001fb05a3f69c63feb0590c9febd1f76164c44123538f67e4c9fd6f8d6393908f80c01d87000020f69c63feb0590c9febd1f76164c44123538f67e4c9fd6f8d6393908f80c01d87204dea6406996a98efea88a66bddbe7f9568093185b08c865b1b664ae0e594c7be07b165b659c3d7c15bba69e00c837d2a599526c6ec00000000003270c21afb4e1ffc000cf8b10001fc000d0b2300f0d1ca8f807aedfa439ff530b2653ae37bb94e6af0d1ca8f807aedfa439ff530b2653ae37bb94e6ac69a0bda7daaae481be8def95e5f347a1d00a4b43016cfe921690a750621948774a88522d4af9e4167a605797abdc8adb414aa254c2e16c43b95e491c1965eb90c528224a600000000f6f8f1b3377129a483e7c027f8ea7df7d2378de902f0788b132ba87c19c29f2f000020f6f8f1b3377129a483e7c027f8ea7df7d2378de902f0788b132ba87c19c29f2f20970ad5ad9687bcd4e164c49064780b2b2a038c942a81f7f939543dc0447996110031331182f4105cd8a4690b82482ec4c09197f5e9000000000022d91cf8fb4e1ffc0006567a01fc00091ca701fc000bdc0b005964edbb7dea08cb0987faa03a37a2295c19f4105964edbb7dea08cb0987faa03a37a2295c19f4101ec5c66e9789c655ae068d35088b4073345fe0b030167d2ac620df46eb74cb2069f69c30965f6c899a134366ab95e41c894293e0d987a3cb78176fe852a309faf101883bb100000000f718902044925ab8ba5089667a4c2a1e45b855eb4388d21c1b14e1d05bc1991f000020f718902044925ab8ba5089667a4c2a1e45b855eb4388d21c1b14e1d05bc1991f20c3aedb72e0902bd6da0a97cf554bdbe6aa6183fb075b4aa3a13fafd81f430e200150046adb767e71c9cd404518f190faa10ca9b9b800000000002e65348afb4e1ffbe5be0001fc00011beb00a7327f6d42206d3642c4633c4b6b10919202cc8ba7327f6d42206d3642c4633c4b6b10919202cc8b6d4c795644ca86f717628ea27f0af13b0ea70eb7300d2be4cbd0faf7a27695a4f11690ba772a32c9df368f0558998681d697e60888b7127314dfa8495096050638d8507c9200000000f735ca801b3ed2a87a0fe2838a38a56d72239fd0c4e3877e80cc280090c6f8e2000020f735ca801b3ed2a87a0fe2838a38a56d72239fd0c4e3877e80cc280090c6f8e220362c9cd667b23f106f2fe366206f8e1d7353c5185de1426e64fabbc2ebe2856d00a1dbf97a74f90b10f8ebb6d919f21cc2cf9e2a13412000000022da8162fb4e1ffc0001980801fc0001c2de01fc0002787b0065802f3ece78b624b0739a8002fe35327ab85b7065802f3ece78b624b0739a8002fe35327ab85b703864c3d41a45675756b2543a0bd787a1a18fb4d9308cf9b3235f77637f144728584ca13d1d3fd47450ad392a510beb2425e0d88f6a3354f0cbdd26d4e6152d38899c025aa3018b3277a4f4a3667225def8a4f83000c086719cd9000000f773def21e01af33f508b4e978631b99405fd1ad3947984d3bbca5b41b221175000020f773def21e01af33f508b4e978631b99405fd1ad3947984d3bbca5b41b2211752071e06128c6220c4671d4582596eaa9528757fc86bfd42a7e6545314a2271c2c501cfdae7bd25128cbaf6e27f37b9bd0e1024d4d3fd000000000023b9cadbfb4e1ffbe35e01fc00015cf101fc000467dc008a108538dca5b073f24fb8db78f06ab6a0aec27e8a108538dca5b073f24fb8db78f06ab6a0aec27e23baa2294dc2c2f7b6e6fa3717074afef3ef2d783004f1a3407bf953809815243d539d316d2b055a57ff6c5412f31d98f0d5ea84f54511fa9f02ddd6d7f8751505c560eaec00000000f7f3a36e13bd406d5b9c9a19b6c67c5051f7a29e6596c1413326b98c00cad909000020f7f3a36e13bd406d5b9c9a19b6c67c5051f7a29e6596c1413326b98c00cad9092009d9ca008cb9263341c196659ea2f751507cc6b6199a9c5b6d40bd136ea3f3f7001d328264ad882a524f8fdec5cadc094fec10834b00000000010000000000000000000000000000000000fc0001979e01fc000197a101fc0001a33d00954c2b52b2f86d89f81b8eb64b0944a1b1033e38954c2b52b2f86d89f81b8eb64b0944a1b1033e385f9227e2d862ef10a8aed1df196e5267accf22023000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f8293d83dfb38fa7a6c34928e9171fe6a112d5a5b1d07592d59f37a23ed0a00c000020f8293d83dfb38fa7a6c34928e9171fe6a112d5a5b1d07592d59f37a23ed0a00c20e0699697fd9e5d90cf616f1f65e6172be9660e8741e431a48b5b280ec9c54aa001a01a6124dd32d31434325f8b39e3133ca643b8c3000000000034348bbafb4e21fc00014c6b0001fc00014cc400894737fba2d8ab6dd337538735ae0a74b18cd19a8e4960713412ea367f0a11c39808c2e77b83048b69a9e3015032f43608f55847cfac26a1926ace9b30803d3e3a2593dfd56111203f3f7c562d1df639d57376d1994aff17260cfbfa576bfed870eedf234bec169e2f8e6c44da00000000f82d3b1184dc6c6f444bea666c1b0da5e0d58a4a29b036e6c21d9e26ec349b44000020f82d3b1184dc6c6f444bea666c1b0da5e0d58a4a29b036e6c21d9e26ec349b442048ba30ad4c27e9c0e3b495b609c15987832ab0f4f22d138dbde025c25e500dcf00d5918187a24fbec74eba87813da01d4977383bf90000000000037ffd56fb4e1bfc000d63490001fc000d640300336fd9a1efbd7983dfc291e482862541dd50af197d354fb6b06f9f41e73aef311024f576db99e6c365af4ce6e6ba9ae427611b7164d92adeddc6c7dd308458274be8fddb6b8685d753bb151ebe32a9021fab91228611a81c3c70b287b607a81388b46aabb16518494f9127776600000000f8ef5516cb8f36418e42dc9e078b26b0c4b1b9ad810019974686fb9a6dc88206000020f8ef5516cb8f36418e42dc9e078b26b0c4b1b9ad810019974686fb9a6dc8820620a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e12220b8c3cf751fb6bcf3b11f12e6406cee717c1ad0000000000235a9dcefb4e1ffc000ccadd000000baee5acad0f663430ff83c4e9b9fcb0122789520baee5acad0f663430ff83c4e9b9fcb012278952064f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d730015ae7a4f88fd79e4659c4b24b32f24d1e92106b867a2c23d1d084cfedd0e2766edd3f0a77f274acd4d1d53fb1ff021800000000f94177aabacd11c12c92b1d5ec28b8ee9f1c07b220ab783cbf8a1a21cf6a5f55000020f94177aabacd11c12c92b1d5ec28b8ee9f1c07b220ab783cbf8a1a21cf6a5f55202048b7ea90f351d942342361942f53cc52eac2b6d2df7aa5cde9ca4f832e699401ad1d4e86ad3a26c56694ad85fc4e14bb01a0244700000000009de6f7dbfb4e1ffbc8190001fc0001195600365a7fa9a52936ee5272729a4011c8a00c0351d3365a7fa9a52936ee5272729a4011c8a00c0351d3ad1d4e86ad3a26c56694ad85fc4e14bb01a02447309993c900fc49b020d4050981a45281cc71274196c57c9405f7ea8d82823b2cb36c04a2aa363111d74e383bdf9fdfe25400000000f9b4e4b1c35b8890d0ef29ee2c8ba7e600ba9acee68b100d24f4c30f190f07b6000020f9b4e4b1c35b8890d0ef29ee2c8ba7e600ba9acee68b100d24f4c30f190f07b620a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e52b046b8be830ef6606eb16136766fb8f5a378f4ce000000000022dcab9cfb4e1ffc000ccadd000000e148cd41cb7a2aa954707c3a5846ea7927d7c835e148cd41cb7a2aa954707c3a5846ea7927d7c83564f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d7308d4afa904198af1607c56fd3a1e8fa546dd2940e603c87fd64905a5eb86334046a7eb8638e36a2dbdb6ca59fa8e6886400000000fa6350305c1ce0de594787f20ff7ddd0c35a4cbdf10c8a9956d833ab6fdcd225000020fa6350305c1ce0de594787f20ff7ddd0c35a4cbdf10c8a9956d833ab6fdcd22520a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e030254e4408d72c5c1ccad797bc8c1bfd869d91c24000000000023a44db1fb4e1ffc000ccadd0001fc0010e71300ea33f7129398e7e2436a712ab55fa95a2c0e4cc6ea33f7129398e7e2436a712ab55fa95a2c0e4cc664f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d73000ea87eef15f38c1a844d77348e687794c601277011c933026cdfdb649524632b055feea3539abc48472cb447d281d6500000000fb1f0a8cd13a1ed6e11d83d906cf3cd42114e36a762e214e04f6f0bfa698dbc2000020fb1f0a8cd13a1ed6e11d83d906cf3cd42114e36a762e214e04f6f0bfa698dbc220a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e1d32db872659af4d0bd7c6f8f7e40f40564c4fcea1000000000022d3c081fb4e1ffc000ccadd000000083a4e9632bcb5c6490a92b3c3b05979bcc866f5083a4e9632bcb5c6490a92b3c3b05979bcc866f564f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d73002ce863d0843ca66b4a64d94c0d84ec15980ea04e4444ac4d4188f38cc0da4d6d2360b8a2046725b682862255af6a48c00000000fbdcb8ebb8b7b0536b8af0bd89b5f973fedb880b51d03434767eaf9ea7443bb6000020fbdcb8ebb8b7b0536b8af0bd89b5f973fedb880b51d03434767eaf9ea7443bb620a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e4a999c0b640e64f1d95e90b4e6b75651cd9581d92c000000000036cae7c3fb4e1ffc000ccadd000000982169553d0e618637a1cc6847b185baa50a2ae4982169553d0e618637a1cc6847b185baa50a2ae464f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d73017f2a4f37de1f78a0d356835de99c7639d8daf824b0d432b2a7c01a921f6a8cd4028272e2962f7d04abf9bfd5a77ab8e00000000fc07e381f05476042949b584f41fabd582e6a54d70657b8ff39fce58af62eb53000020fc07e381f05476042949b584f41fabd582e6a54d70657b8ff39fce58af62eb5320a8e7d1287b0354408fda5a65427a636c7c5854a957b94c5f993d727450ffe34e2a473290be126b36c0ebbc0ea853721bc67ea994a80000000000235b9622fb4e1ffc000ccadd0001fc0011030a0087e9edf19d1998903bf17a10a954872f429ced8287e9edf19d1998903bf17a10a954872f429ced8264f2b2b84f62d68a2cd7f7f5fb2b5aa75ef716d730090f1ca955443740346b5b4b0bfb8251f040074b5a2feb77e54add831bf34aaf1d84207691f6f5aa5e702152a496fadc00000000fc196382366234f4645215261ca7e62f53499345ec1def69289e47c0c388dc6d000120fc196382366234f4645215261ca7e62f53499345ec1def69289e47c0c388dc6d20151b4f6fbc7351efba1dd1c36c733978a184561af7497b25b4a8a3e0afec0e7f016608134feb91cb878b26b977f1d7983a2f14452a4248000000258b0cf7fb4e1ffc000df5420001fc000df56b00c346a8ffbdcc80462cb69a6f524388a5f496fc6ec9a9263ee8c8c606c449959c48978ba70d4a097bfc86e599d56c282377dd9510ee62c55fefa553b1308d0651a04f9c243872f613901a1eeb2fa86f3e9a65168bc39941790783d9189a9a7876cedb0c6d7ff7d49fbc88a7191100011348d8f97063cf6ff602c14bf59b5ff501c8bbf401fb8f3001fb05a3fcc330b0afdf27d07997b93277a3942e28f7cf4fd043b7ee64b6b5c16173c936000020fcc330b0afdf27d07997b93277a3942e28f7cf4fd043b7ee64b6b5c16173c9362036c97361c1b5b664eeb743d04fcff7282e94a37732b99779d027dfafb030c3fc003d2324a9cadcb2ea6579a7348ab70aa933472bfa41000000000381198efb4e1ffc000541190001fc000541d400e73be15c24f67457c2337a8c99ca1e58aa68598d7200be0fcbcb2c10e968ea0b5508bc3424c9c68bda952b3b45775c0af85fbe2e2ab21549d86beb0a3089aaf743d70a26ecd18aae71d8e2ff0bfc98a51511f83c8acda856e3f5d7c61c21ff4e19a56f02ecfb6ee014097945e300000000fcdeb237fae2e669a85a86e8077e608c6939ef0f4f9e49a44e5ed6795572e6a8000020fcdeb237fae2e669a85a86e8077e608c6939ef0f4f9e49a44e5ed6795572e6a820d3a8d64ff151b1ba13683b26008256b24aacec6f9da5c0066ca64c10a73517ce012c3e80b009a279f6b8cd5db9fb3206f14676366000000000002356861dfb4e1ffc000b9bb301fc000ba63001fc000bd21b0047618a2082ca728a4d9397643a7578a735a44d1b47618a2082ca728a4d9397643a7578a735a44d1b1ec5c66e9789c655ae068d35088b4073345fe0b0308341875737a85768a19cfe8c6c220b594bb18131adfd2fb44e386f7b31253aeeb48140170e29db98507489c7b1f792de00000000fd21cf50c8f2f7e475b7092a5f136129b12d30e9ec98b03614ea0788fae2f888000020fd21cf50c8f2f7e475b7092a5f136129b12d30e9ec98b03614ea0788fae2f88820a8e027adb039814f1d9a37963c233d9d768e2fbe810c79c0818a5fe103a2505c00582f33bc9bb2587d4d87dfbb37d44b1d1c201fe7000000000022dfe2e0fb4e1ffc0006567a01fc00068cf701fc000bd9830055f851335398fd598265dcc41dcbefbc307b609955f851335398fd598265dcc41dcbefbc307b60991ec5c66e9789c655ae068d35088b4073345fe0b030046fe8b4fa7dd4fb52ac2a77b4ef7dcd3f4ee6c940789144504c95390d556eab1ed97db4d9de695796fc0bdbf0543cf700000000fdb15344c0b81fa9204adadf4fbb285a8e57c6079071c1e6134ef1a28ff23630000020fdb15344c0b81fa9204adadf4fbb285a8e57c6079071c1e6134ef1a28ff23630205b016215386c035a42042a93736befccdb87c30cb90adc3b1279da58ac57cc1406928d5d3df4acda874f594b59a88a38052478f10d000000000036b87f1cfb4e1ffc000cf8b101fc000cf98701fc000d0493000453c5b78e603d51a58a56e7a3b6a4bcfa5b1bca0453c5b78e603d51a58a56e7a3b6a4bcfa5b1bcac69a0bda7daaae481be8def95e5f347a1d00a4b4308a1a6b956acbb6cc1c4fc3713ae482d84ac9d3e00ec86ffe25a56a717b748564128c97f38e99bfe7292fd4737ce5299c00000000fef106ff6420f9c6638c9676988a8fc655750caafb506c98cb5ff3d4fea99a41000020fef106ff6420f9c6638c9676988a8fc655750caafb506c98cb5ff3d4fea99a41203933d2e77a9b59df4215597e381942291a23aa6765386dbabb04117c1018988001d5faf54e1d7675b61cd63f569ee38bfaee9501b800000000002d30a810fb4e1ffb3e6401fc000b253301fc000b322c00ce2342a602ce6bd150809591377ecf31971558cace2342a602ce6bd150809591377ecf31971558ca05ea03a6c9dfa67e1837b3c14965ba3cb53bce7230842476e8d82327adfb9b617a7ac3f62868946c0c4b6b0e365747cfb8825b8b79ba0eb1fa62e8583ae7102f59bf70c7c700000000ff261d2c1c76907a2ad8aeb6c5611796f03b5cbd88ae92452a4727e13f4f4ac9000120ff261d2c1c76907a2ad8aeb6c5611796f03b5cbd88ae92452a4727e13f4f4ac920593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c0c456ce31778e3778c88a87ac36a1a8bd4aa5bdbe9000000000036bb0ee8fb4e1ffc000cf99e000000b14f661da8227a41acef9f8096df2afd2a192aafb14f661da8227a41acef9f8096df2afd2a192aafc69a0bda7daaae481be8def95e5f347a1d00a4b430967796952922dcc5208a3848ab85a787e4592df2d8ce36a29369b0b3a9576073651075039e1377873aa8c67514ad2726000167e05b1b52c7c896adf20035036fe1d30dcefc9c01fb8f3001fb05a33005b687978344fa2433b2aa99d41f643e2d8581a789cdc23084889ceca5244ea800012005b687978344fa2433b2aa99d41f643e2d8581a789cdc23084889ceca5244ea820593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c093de7795dfedb896cb65547535ed92f27489d8df3000000000034187ca2fb4e1ffc000cf99e000000ec83a5f23ec17737f590153eb7eed16f7b2f1327ec83a5f23ec17737f590153eb7eed16f7b2f1327c69a0bda7daaae481be8def95e5f347a1d00a4b43080f8efb42f65ed9650078785be5d13e6e90eb9df87a99261d4de34df2b4b79a9c9b8c5e1aec7ac068ebef14636ceac4c00018feb00404d6f765856c95e587b2523a365bc725801fb8f3001fb05a312de3ea6678dadb1db529b7fa98762160625055de2aa34e757c93c136233f4a200012012de3ea6678dadb1db529b7fa98762160625055de2aa34e757c93c136233f4a2206793cf0a4aff111f1d61a13002686c066afbfe5da974cc7dec8cb4cef736dd8000542bd8c9d87e1cdd3db777d29c35e9903b17727a4120000000d4186795fb4e1ffc0010903d0000006e52a40d2dc4dea0ae7ff2b299283de0f2798b0a12deb4ca2b5a05b6eb2ab25bb5fee75d3287b3df0d5bcbeeb459af40f97fcb4a98e9d1ed13e904c8308a3dbdeee728fdec9cea3508c19ece8d2e8330b666e25666b1766ed5f44609dc8674dab4163e8574f4adf2e936a209d501c623e2d926af5eb52dcc2b931993d3e52714511801c1161c96de3dae28cd7f20ff8c2aa7b94b866d7601fb8f3001fb05a3143dcd6a6b7684fde01e88a10e5d65de9a29244c5ecd586d14a342657025f113000120143dcd6a6b7684fde01e88a10e5d65de9a29244c5ecd586d14a342657025f11320593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c13838ddf0c05bbc0edebee7e368f4dc6306d524af2000000000023a417f5fb4e1ffc000cf99e0000007395853c0be5fb0f0348aff8128979368f52b0ee7395853c0be5fb0f0348aff8128979368f52b0eec69a0bda7daaae481be8def95e5f347a1d00a4b430b928fa4e127214ccb2b5de1660b5e371d2f3c9845077bc3900fc6aabe82ddd2e61530be3765cea15752e30fc761ab7300001b5f25f8f70cf8d05c2d2970bdf186c994431d84e01fb8f3001fb05a31ba9b400a99c8ab19e2681db0e868814aa273e8eaa13615979a14c50bbd53f4c0001201ba9b400a99c8ab19e2681db0e868814aa273e8eaa13615979a14c50bbd53f4c204c3fd5bb504ca179596113aa8e3e27aa1488860edb81269eb18a9ca900b4a91b017c706d1b78fadb609fd92ff5929901a706c55877000000000058162c0bfb08aefc000cf9830001fc000cf99b00f74034f58c080be74bec51165c5ffe60ed1a615f96375e263814e1d54fc3297fe893dfb5a9c1a9eb6443411c39e405d2520567d4f6b041c5c550086230b006ed30975f322c830001d1b3c2e2f14a4ef35445431356f1c5b93c2eedd9c7ea24c4429d27d45f2fd701733ffd65540001f2dbd9b0a1f541a7c44d34a58674d0262f5feca501fb592501fb592620107ec50e81880dca18178bb7e53e2d0449c0734106a607253b9af2ffea006c00012020107ec50e81880dca18178bb7e53e2d0449c0734106a607253b9af2ffea006c20593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c117663ee06b0b159308edf41150954372a730aa6a50000000000235515b3fb4e1ffc000cf99e00000004d65ec5142719f58e31f4510dda3c810a84364204d65ec5142719f58e31f4510dda3c810a843642c69a0bda7daaae481be8def95e5f347a1d00a4b430b6e979f20241cbb73de7451779e8e059d9cb75a74b72ea6862d7ac703dc2ac07d86cec39b6e8923b55fd54dbc6177c3a000135d9eb76397d05b43b5cd8da7ccfa8408bc89ab301fb8f3001fb05a32e48651a2e9c0cb4f2fb7ab874061aa4af0cd28b59695631e6a35af3950ef6fb0001202e48651a2e9c0cb4f2fb7ab874061aa4af0cd28b59695631e6a35af3950ef6fb20593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c0101e19b30edacc8bd047a72d6b12b79b3f1b2babd0000000000369521a7fb4e1ffc000cf99e00000063f16c50b9cd1dccd8465e1802749bd00dd49a2d63f16c50b9cd1dccd8465e1802749bd00dd49a2dc69a0bda7daaae481be8def95e5f347a1d00a4b430943a88959611417f9e8ce4e664e1d9c6a839daae14f54ae8e78bc5ef6ec1524d116efca49ecd5c57dce31d90015a51ff00011ffbf1d32541dcb8f5555305295704a9ff9adc2401fb8f3001fb05a330110b4643c2d8c7521f27ccc2a6a70579bc859087fb95facbb831b3a3d107c700012030110b4643c2d8c7521f27ccc2a6a70579bc859087fb95facbb831b3a3d107c720fbcd42341652da33e977bab8bbef42d0f053f93e9e2748f3f39881d11e28910c017798d43ef1f85193b1a0e5a7ab7853a39d27f0334060000000a6469a72fb4e1ffc000f01930001fc001046630057656569e143ae0cc0419020708c8ce5f4c776e452bfa12608d37422d52423c3a71f9574ffa8267f535e571f5fb89e31f634da8b91769ea4dd252e19308cf6a03c7a0bd8c38c1fc536a013f93afc8224cbfc79d8b0157c7080117ec9c1c60198c3fb3886ec472aeaf80bd5fffc0001c3f93922e89f4bb3869da0c18d8e30dd91019bb101fb669601fb27103971dab9691efac06e4ce7a5483131373e84726458924fe48b7d541791693be10001203971dab9691efac06e4ce7a5483131373e84726458924fe48b7d541791693be120926c6d0e0ce17a51dadcdc5be4f4cce0175d8d7a147e294580e3080d6a22f96d00e5cae595965e89fa9f94152f57b315ca504ee1b300000000005c3fb0cafb4e1ffc0011098b000000b29a8f14049a111260586f489d72cfea1ed8ee5d492df4065de3d5d44692934635d826255f7a60f80e7e48253baecd886fd539601fd5e95efd61534d30b92d4ef819fe283a307e6bcd500d8cd35e9a7b779dbca59bd3bc77b3bb3611c370258aa6dec13d0781e0b53c911bde08000161c274080f47a95be5372ef8c69bb60ab1d4ca8201fb8f3001fb05a339741ad83dd791e1e738f19edae82d6c0322972e6a455981424da3769b3dbd4a00012039741ad83dd791e1e738f19edae82d6c0322972e6a455981424da3769b3dbd4a20593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c0826c998cd53845caec6858f3121e5d3a88df6c7a3000000000023a390e6fb4e1ffc000cf99e000000bd9857229d4c0509c753afc85d264fe2e4f344a3bd9857229d4c0509c753afc85d264fe2e4f344a3c69a0bda7daaae481be8def95e5f347a1d00a4b430b6693296894820bdc3c0ae76f357e544847f10a68f0046f53745370dbe861d57e194ddaf7ff7d5e73cc3f240515c448e0001ec7bf3b9bc72eda38c80bb7cf16e294e763e56b401fb8f3001fb05a33979cfb79c4562e819aca69ffae2ea84b9b8f29bd89bdc68be67b88c6f31bf990001203979cfb79c4562e819aca69ffae2ea84b9b8f29bd89bdc68be67b88c6f31bf992067a0592b5510496cb42f2d784cc3b933a0156b10c8b54e440673bb87c57dbb01011353eea2d4fbc06aedc288e493b70de32b3e977f0000000000adc777f2fb4e1ffc000d5e0f0001fc000d5e4b00d8155dce6238737a6af04e068bd92048e68a7f51212e07f7407be541b585ff0a8225fa1afbcc9ac8dc82946c9cee9ab3e8fef5a5d641a57bdf1523c030a73d8c1e640d29e2257042a39bbbac8d867f69ae252e146884816b98ab0d0526ed4992d9cff22ef04878423f66583382000171b5c04007f6af71d99893478feb52df0f5a770101fb592501fb592639b88e537c795f0b093c951539695fd4819a91a542b247ebd3a0ddd6a4c1c43900012039b88e537c795f0b093c951539695fd4819a91a542b247ebd3a0ddd6a4c1c43920bb600d779c7be93a83b9d7878fb38b0b1b7ff1390b231c5da8136b674cde822f01fd9cd0a5165717d4b3a17afddc669f3fd14efbb5000000000082a2e172fb4e1ffc000ddfee0001fc000e0d6b00f5cd552d14676526ef325757eddcfa285b15ac34bf951db34349385992e0303f21fd7240e44e4b0222319c7fcaf88f86259ffd3fa8430e4665f2e1f53090d98ff5c2f2970197ce80ca8cba9431f7dd7cff5d9fc9c4e99c2ed06e598f273d31dad8d8d05655c8b04599495cee2300018e976c7a2f79745d70e41aab1e61cb5f4db4323c01fb682001fb01bb3f43ff3539e5a4fbcc88c7f031a544fe7e62557b5963cb7e43157ef73abfb13d0001203f43ff3539e5a4fbcc88c7f031a544fe7e62557b5963cb7e43157ef73abfb13d20476ad8662b3be5582b98569b76f66d2eecb59a943e9fb28bcbd23a10d53817bb01127e174ed242c758d4db9b7d5b19c1e0743728960000000000b29d5bbcfb4e1ffc000de50401fc000def0c01fc000e366a008ee38b4c9c407b21612862db1ac4e98a6edacb4b62026629f37f587b1dc70ccbc6732225803db4e3ecc3795b4c3e8c5b840dbfa092df1395237f2f8a30980213c5fa8031aff096b8a3eddeefd0584a0e5c2492f631ef67941e082763250e2615975db1f1bfae631f80d41d839a000100120432e9d299caad204ff1ec0c515babddc28601fb8f3001fb05a340784f3f9a761c60156f9244a902c0626f8bc8fe003786c70f1fc6be41da467d00012040784f3f9a761c60156f9244a902c0626f8bc8fe003786c70f1fc6be41da467d20593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c02024eb44eadf4a67de93988f1400bfd5fd6fdbf830000000000340ae50bfb4e1ffc000cf99e000000f37ebd7e83f4185ccc5fb617a7ac9e09c11ffc12f37ebd7e83f4185ccc5fb617a7ac9e09c11ffc12c69a0bda7daaae481be8def95e5f347a1d00a4b43082f60dad4b7b498379d1c700da56d4927727eab4387a793b861a96df47bdabe5666c270acf04b5b842ab54045bbf102a00013e8b10646ee9d6c28d75c280b357dd3a9ae9f96201fb8f3001fb05a34bba47ad7330a358cafe2890f1578f874006a68bdc7b786a7c1d440823e683d40001204bba47ad7330a358cafe2890f1578f874006a68bdc7b786a7c1d440823e683d420ca7dbad69767b30fe851c08c80df2cc8398bcc8c33df2d03bcb810485f3d8d31006e6c9189021b6e38326dff6886104054a110990d00000000005fd916b6fb4e1ffc0010871f0001fc0010874300bd8b7dede4dab5e22b84ee0f3dace1c1021add92c9924137fa318dbfca7cabf3a1127fc358acc74d6e6c9189021b6e38326dff6886104054a110990d308ebfddfa72f3140798b6c0d89190164c4dc569ffdd95bd1dd43e7f54f1405c1927b37b499623b4c806ea396bea40a84d0001b98306c317875b12fae8a85c85eb23269168981801fb682301fb01c15b246080ba64350685fe302d3d790f5bb238cb619920d46230c844f079944a230001205b246080ba64350685fe302d3d790f5bb238cb619920d46230c844f079944a2320774441a2d4ff6133747a8bb1b5e4a9a21bb73c4b77cf31e85bda68f898949db0013f978f2c099e310cac9e854b99bc981c8fdcade2000000000023a5327efb4e1ffc000cfb4d000000ebb7d8141ecbdf2abcdc3ebe25420b9425745293ebb7d8141ecbdf2abcdc3ebe25420b9425745293c69a0bda7daaae481be8def95e5f347a1d00a4b430b44cee83a79fa151527e527f3f4f5ba022e73ae8b0d913c4185a45c2a129aef935a585a7a725edcb36ece72a957586880001f460a07a2b0dc932e1d8ff2dee2b984ac415dceb01fb8f3001fb05a35c6542766615387183715d958a925552472f93335fa1612880423e4bbdaef4360001205c6542766615387183715d958a925552472f93335fa1612880423e4bbdaef43620593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c0f62555d44fc8d089674bab5d090a48825bea701b700000000002cef2799fb4e1ffc000cf99e0000007ef7c15840f96c603fcd29409a70f77f878d25d87ef7c15840f96c603fcd29409a70f77f878d25d8c69a0bda7daaae481be8def95e5f347a1d00a4b43086d0a2ca6f434eaa47ff6919ecafa4fc3b012b89c62a04835a24c00faf62c3d30d3f8755c33a7abc595e96fb5b79594a0001972a33056d57359de8acfa4fb8b29dc1c14f76b801fb8f3001fb05a36029fadf3355a31c6f841570e76bcdf5636378c65ff1da8f580806602752694b0001206029fadf3355a31c6f841570e76bcdf5636378c65ff1da8f580806602752694b203e14ea3daa62c03d9ed56e8895b5d98188711c49818cd0add43d37fe512c93d1012a5d83dcce0edae361a62d8bc2a308a87e29a49b000000000059a9ab6afb4e1ffc001079fe01fc00107c0e01fc00108203001119c437dbe2c3aeb4a3c7d1e29380738e3372433e443eba6ce82ca15b203d10117c653f26944256cb505749178fb4f731643d9aa56c54e504f9cc6e30a4adf9fa35bc975e52e3f667e48ff3ed7ce71f8ecb85d5ec728596f7fee735c2f857fae1569c8b4c6839ca849cba42d1000197ed64c04be77ef571fd5624c0f7705192630e3a01fb8f3001fb05a36071df1e3bf80ba6cb9795bb2a82ef426cf559b7711e555af45fd8da7fb629b80001206071df1e3bf80ba6cb9795bb2a82ef426cf559b7711e555af45fd8da7fb629b820387368b816ed3599d758185ae60d943afc22201e94e06ffb3dad30a3ddc6756b0005ccc78c0358f7b71d254b28c7287da9b39b81f400000000002d20db70fb4e1ffc000d05b30001fc000d05cb00434dcdb7115427657cf2936248b62a97b9969795ff1266f2c8aa7b1f93a15b8882013af424d7d9e805ccc78c0358f7b71d254b28c7287da9b39b81f430b4e545a909b1916959139eaea845262b0aadec1c5cf555922bb6e6d1804343e6490428a382a0c01832fc70c50438fea6000152cdd176257544a263ecadb986ed72375589a8a401fb682001fb01bb61d33f478933797be4de88353c7c2d843c21310f6d00f6eff31424a756ee7dfb00012061d33f478933797be4de88353c7c2d843c21310f6d00f6eff31424a756ee7dfb20593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c15888380d6096d829d6864cf6eec66812266839e0d0000000000340cb05afb4e1ffc000cf99e000000b5b414e1a68e36a25df214ac6eba35782a0437dab5b414e1a68e36a25df214ac6eba35782a0437dac69a0bda7daaae481be8def95e5f347a1d00a4b430a6a63376eb861bda6afa09e28e39ba40cdfb877ee6f9aace10eaccd4caafe8d9243f2f2c0ef982a0766347073cc199bb00017ada3e486409b39c94a0833c8d782f35bc24e96a01fb8f3001fb05a368512af99ba954cba495e96651a8d730880e21437a873fd9309b54ea9e3b53cc00012068512af99ba954cba495e96651a8d730880e21437a873fd9309b54ea9e3b53cc207459dbe6d9b1930f8d6bf4d0872b2ed6af58baa2f0effe608e6e2ab0c98c148501f30f8dc6c5b956089b30b3dc91867a3b72620b2f0000000000b92f8494fb4e1ffc000faa6501fc000fcdc401fc000fcdec0044b7348492de6612c17d0aff5a3f6fb5f338d57ab2f70938b1cfaba9eab8eee718a48f292e1d5180d86df99cea20e4fadf223310df529ce645f0db2330a28a648ac2b271105426f11a070d3f4854f812c3fd0241860afd511a7ac76e681210505ed41121b141e377a73faaedde0001e33c1f9be807b975c0f5e1c0e3c63175d9e55ea901fb8f3001fb05a36d1b185ba036efcd44a77e05a9aaf69a0c4e40976aec00b04773e528633209660001206d1b185ba036efcd44a77e05a9aaf69a0c4e40976aec00b04773e5286332096620593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c18a93e60c572add22525a10a5554e6f6a4feca49fe00000000002ce4f2b5fb4e1ffc000cf99e000000f3a83d259634fbfc3e3c4ed50cdcab6598fce20bf3a83d259634fbfc3e3c4ed50cdcab6598fce20bc69a0bda7daaae481be8def95e5f347a1d00a4b430b8a2161c64bfdc7d621df51de569911a219f718bad4d6058dcca9bddf6696d43ddc4c1e3cf91640c93f820e5680efac30001c374f016ea61e76aab79b8bb95a1ba0e6e3eee6f01fb8f3001fb05a37135069642e1a72807a383fb5a14b9af6758292fee53fe2a7f7ac6f528bf70190001207135069642e1a72807a383fb5a14b9af6758292fee53fe2a7f7ac6f528bf701920593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c1063c03764190123b001e65fd3aa12c030df5bde82000000000036bda427fb4e1ffc000cf99e000000b920a2229f777e360b7da76885a556bb439533bfb920a2229f777e360b7da76885a556bb439533bfc69a0bda7daaae481be8def95e5f347a1d00a4b4309472710b11e34dd5f6fa0d43cdde23ddb33558be1539cc7275cf06ba2d82c6ba0c712e7022752843f411e6702eaa736d0001f9956e70daffa263e8cf29fa6557b7b630a595a801fb8f3001fb05a3754b89dae8db20fc4cee5e3adb07b146d7efe508a66fa0a8e1094675b9daa35e000120754b89dae8db20fc4cee5e3adb07b146d7efe508a66fa0a8e1094675b9daa35e20593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c19ad66f3780f47e83479e1846ecca44d71ba5a902f00000000002ce92c5ffb4e1ffc000cf99e000000e65f1647a5477a20d178b12c509738d7a35ff312e65f1647a5477a20d178b12c509738d7a35ff312c69a0bda7daaae481be8def95e5f347a1d00a4b43099b9f0fbeea3822cdc5b3654dea52103b3d9d5f01db4201955ea3689074d37da4711d8f313d4b5458eef3395aa75bfc7000146d938862af6d9a291e26c0048177db2892a710b01fb8f3001fb05a37718edad371e46d20fad30086e4acf4a05c2b660df6ae5f2a684aebdf1be42900001207718edad371e46d20fad30086e4acf4a05c2b660df6ae5f2a684aebdf1be429020593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c1feea83c4756a349e76b9077636dd04b3306bac60d00000000002ce3894dfb4e1ffc000cf99e000000c0e3581e5165c63790a2b8d2670fb4a1917cd4b8c0e3581e5165c63790a2b8d2670fb4a1917cd4b8c69a0bda7daaae481be8def95e5f347a1d00a4b430b675a1940be872b6a0d4e1696bb39ea38179933a1bae02ae1eaf4b47f625bd939482f8791eb38925af47f73be027a64c00010498ade3c80045c2a7520e921180ae1c39da5c5701fb8f3001fb05a37a1ae04de7582262d9dea3f4d72bc24a474c6f71988066b74a41f17be55526520001207a1ae04de7582262d9dea3f4d72bc24a474c6f71988066b74a41f17be555265220593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c1cc1d71953a4a45bd11d458683bbf2ef794d6d6e3d000000000023a612a6fb4e1ffc000cf99e0001fc0010f2fb0063c8d3ed082eb5d476a0940ef9c3fadafc4c5d2c63c8d3ed082eb5d476a0940ef9c3fadafc4c5d2cc69a0bda7daaae481be8def95e5f347a1d00a4b43093943908436a934c08582583b08cbcc50b4478bb79b7718789c25eb0ad2f3e5713ad4c152d4b1fd13cfd12bf896072e600017478cfd163788e3bbe09645776cf59642f28e37901fb8f3001fb05a37e56cc8c37501f3db794a554deb4287ac61c83635a0dec6d0f8e0b54ab14f8cd0001207e56cc8c37501f3db794a554deb4287ac61c83635a0dec6d0f8e0b54ab14f8cd2095f18528a48b7308195ec8201220efaafecfbf4df55cc2c8ab6b518733c22d63010e3edcfe65ca42dccfb1cb826562a46097c6f044412000000022df662bfb4e1ffc001066880001fc00108203006afebaad117b22669d50cf8bffc7863662b1d7e16afebaad117b22669d50cf8bffc7863662b1d7e16c671d1b8ae658d8102e47f0bb3f795482a6e215308156eebd6b52f4146a5b3f9686b9712f48980dfa4e8f17b514ba185a31e8d5fa7568c69aa79d9533fa6efd380c27b0c00001390fef6518c3b4b95551fe1707e0f0c398d5580801fb682001fb01bb85f15a31d3838293a9c1d72a1a0fa21e66110ce20878bd4c1024c4ae1d5be82400012085f15a31d3838293a9c1d72a1a0fa21e66110ce20878bd4c1024c4ae1d5be82420593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c1aba3f43f7376b9025296fa73a30c07ccf5266eed8000000000036c92083fb4e1ffc000cf99e0000000f89b9ac5ac8f31255f692a3eb0283d0ef3be4360f89b9ac5ac8f31255f692a3eb0283d0ef3be436c69a0bda7daaae481be8def95e5f347a1d00a4b430ac3026b3e3023db1db9ec8e3b7678761820a2a6e96e7a5d9a39b1894170f9cea7765d3d131d60fa9d17492ba560fb1f9000168c506d43816d1a8389c860c1d162be44d1e777c01fb8f3001fb05a387075234ac47353b42bb97ce46330cb67cd4648c01f0b2393d7e729b0d67891800012087075234ac47353b42bb97ce46330cb67cd4648c01f0b2393d7e729b0d67891820593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c071594bae6e759f13fbc246c11fbd8d97d68911241000000000023a79195fb4e1ffc000cf99e000000762e689e7bfecbe16bfd0e6138eea642ee0513c5762e689e7bfecbe16bfd0e6138eea642ee0513c5c69a0bda7daaae481be8def95e5f347a1d00a4b430a7afe7674de986aff5e2e0a173be8c29abed8b5d6f878389ea18be0d43c62ad1ba66a59e9e8d8453aa0ed1a69697675800019b9cdbfe3568cc0b37f136b00a634c75653f05e301fb8f3001fb05a388251bd4b124efeb87537deabeec54f6c8f575f4df81f10cf5e8eea073092b6f00012088251bd4b124efeb87537deabeec54f6c8f575f4df81f10cf5e8eea073092b6f20593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c03090aa69c8d1a95839e017d1b2b53d3499fa0a9aa000000000034211c2ffb4e1ffc000cf99e0000000799f054652c1cef10d2994fb83d012d559a1faf0799f054652c1cef10d2994fb83d012d559a1fafc69a0bda7daaae481be8def95e5f347a1d00a4b430af9cd8567923fea3f6e6bbf5e1b3a76bf772f6a3c72b41be15c257af50533b32cc3923cebdeda9fce7a6bc9659123d530001711fd9548ae19b2e91c7a9b4067000467ccdd2b501fb8f3001fb05a38917bb546318f3410d1a7901c7b846a73446311b5164b45a03f0e613f208f2340001208917bb546318f3410d1a7901c7b846a73446311b5164b45a03f0e613f208f23420593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c21fe8d862d5042691749e866af337e50e599e64fdc0000000000340d8492fb4e1ffc000cf99e00000018d9316618b1f55977af250cc5d8783617084aac18d9316618b1f55977af250cc5d8783617084aacc69a0bda7daaae481be8def95e5f347a1d00a4b43087d25769002af2a4f050127c73fff03a24935e48f34fecaacd69410787d0e6384b345c78e81b1cb397b43dcd635568b600015bdbf34a0dad860c6ec71523ae39373325225cc101fb8f3001fb05a38b8d1193afd22e538ce0c9fb50fee155d0f6176ca68e65da684c5dce2d1e08150001208b8d1193afd22e538ce0c9fb50fee155d0f6176ca68e65da684c5dce2d1e081520593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c0b3fe432c394e3e96e8804a8e059b1887afc913012000000000034229032fb4e1ffc000cf99e000000b802f02882ed36279ba95674e7e190e86bd6458db802f02882ed36279ba95674e7e190e86bd6458dc69a0bda7daaae481be8def95e5f347a1d00a4b430a1749fecb407bb0e0ab9d6df65ea068dba5dc03e14dcb36abe5cb2b5c6e424683f715ff09ce290d035dbb31add0c01800001a0a0e17bfe82a484fefe348b7569a6d77d29d2c201fb8f3001fb05a38de8b12952f7058d827bd04cdff1c2175d87bbf89f28b52452a637bc979addc40001208de8b12952f7058d827bd04cdff1c2175d87bbf89f28b52452a637bc979addc420593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c1dd08fdbbe79813bc43a306740d2182674141d76de0000000000342b56e7fb4e1ffc000cf99e000000300904176cc6023370b2462964c12c5979b9f411300904176cc6023370b2462964c12c5979b9f411c69a0bda7daaae481be8def95e5f347a1d00a4b4309502bb884b3437d65c0e025e49fb00ff6ea9f55d5bcdc36330b46c8bd18be9126b7a6d7f35f558ef8040f2c2284500a50001337b7fb5d2c531825c3e0123ac3354018085b30201fb8f3001fb05a38e11eb784883d3dc9d0d74a74633f067dc61c408dfdee49b8f93bb161f2916c00001208e11eb784883d3dc9d0d74a74633f067dc61c408dfdee49b8f93bb161f2916c020593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c20f53e3ff160dab7ec3cc2a6b0afa6dd8d36e38794000000000034599a30fb4e1ffc000cf99e0000000063eb51fcfd121e6c3eae23b90b26cd1100217b0063eb51fcfd121e6c3eae23b90b26cd1100217bc69a0bda7daaae481be8def95e5f347a1d00a4b4308160877a911d8bb7d1e75e2320e98cc3233c1f6972cb642424bfcec7c182c56d2c0ebb59e45f788f4d5dbfa2ebff3e3a00016d57707c196e06487d326094c964f258f5b77c3501fb8f3001fb05a38eca4bcbb3a124ab283afd42dad3bdb2077b3809659788a0f1daffce5b9f001f0001208eca4bcbb3a124ab283afd42dad3bdb2077b3809659788a0f1daffce5b9f001f20593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c0e55b79902ab8dc5c126e61ebd5bdc2ec98d80836600000000003644ebc9fb4e1ffc000cf99e000000983259ad7ed51267fb83a8e41bbaa5ab55c632e1983259ad7ed51267fb83a8e41bbaa5ab55c632e1c69a0bda7daaae481be8def95e5f347a1d00a4b430b942e2e50c5cf9d9fe81119cc5379057c05fe15134f85847356b5d1f6a21f29f4a53f61f03338d056edc15a8c63fbbe80001c075993a8336f93a13bb7bbb7e0e89928be4aafb01fb8f3001fb05a391bbce94c34ebde0d099c0a2cb7635c0c31425ebabcec644f4f1a0854bfa605d00012091bbce94c34ebde0d099c0a2cb7635c0c31425ebabcec644f4f1a0854bfa605d20593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c1eea45a388d248dcd7433c8c8113d5d0966069413500000000003428db29fb4e1ffc000cf99e000000cf83406065cb65ce74100f3c35a0324bfc92dcb0cf83406065cb65ce74100f3c35a0324bfc92dcb0c69a0bda7daaae481be8def95e5f347a1d00a4b43081ad0f9be5a88ae62ff54fe938dfceea71be03bd4c6a7aebf75896e8d495d310acc4146aa4820bc0e5f5b06579dedea5000102aa69f8ef6666e7cad6d9323755a0ef3c1b6bd901fb8f3001fb05a3957acb5bb59e253059da86924b5bbd94c1daf5b0fcd313bdb78e43bdc7cad000000120957acb5bb59e253059da86924b5bbd94c1daf5b0fcd313bdb78e43bdc7cad00020176deee4e53c297f44029a7db294451139901bb49f33a2a0ac8bd1b9e744fee201c406356d37513ea70f93868797061aec981337a700000000002d87b4aafb4e1ffc00102b8501fc0010594501fc0010598300cf0ea50da406da09dd78689abaa7c44aad428e3f37f1afe5852c1aece552ed1be61dc898a8db05f06e0e8a6ca912d408dc8369365e947a41d9d0a9d83098fc5928355798aa9237b107935ba606bd749e16f2922d8c4eb6b6c2cbbb4210f3bad09fe7d199aa3884fae3fce0120d0001a5bf8ff04bf1be7f1d98cb952f1b49f8d162d8a301fb682001fb01bb9712e85d660fa2f761f980ef5812c225f33f336f285728803dcd421937d3df540001209712e85d660fa2f761f980ef5812c225f33f336f285728803dcd421937d3df5420593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c1277e135a613d9797db4d7a9d2e51bfe8599d3650200000000002352c5c5fb4e1ffc000cf99e00000020c7f1991e06d09b1f067b049fe6d0af0a20f79c20c7f1991e06d09b1f067b049fe6d0af0a20f79cc69a0bda7daaae481be8def95e5f347a1d00a4b430a8dbccb130522909dc710a65728006732c18441757f12a338cf4a6d8cbd5baf1a484537a6a0542f51bb686e6e546f1a00001ed1131823bcea23ac78af8c01e4d24683d6ecf8801fb8f3001fb05a398ef58c338a0a68e4f2f1d1ee9eb05fcafbb9177d192dac0f698d3d9ba09209600012098ef58c338a0a68e4f2f1d1ee9eb05fcafbb9177d192dac0f698d3d9ba09209620593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c178b5541d75eaaa98f8ad22355a122c55741f339f200000000002ce8c406fb4e1ffc000cf99e000000caf6f1b9916245ce300a63fa2254ada25e0423d6caf6f1b9916245ce300a63fa2254ada25e0423d6c69a0bda7daaae481be8def95e5f347a1d00a4b430b6175b59aba8cc0477d4fff78bd90294f31ebd385c39bc254c7995a5dd3ccb8dc1d8869e247bf63bef8ec79317f479a90001d6ece912cbf02627a4efc3dd37e6833cf367155101fb8f3001fb05a39cb04f271ba050132c00cc5838fb69e77bc55b5689f9d2d850dc528935f8145c0001209cb04f271ba050132c00cc5838fb69e77bc55b5689f9d2d850dc528935f8145c20593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c1bbb948d5d33120f51f2ca02c77a0b69761b719f07000000000022d63044fb4e1ffc000cf99e000000c54ac69739bf492d4328f1bf0d49581ce0b10d41c54ac69739bf492d4328f1bf0d49581ce0b10d417ea623bdf8c5607f0390c85586d83d473fa6a1c630b6ee48c7a71a9d8e0813e68ca09846245fa155285f24a62b0ce9cb0102b1994ec58af8ba2a01c09363bdcc395d41f3df000162e960a3f6b650feed98a266b3ccdf6e363562cf01fb8f3001fb05a3b3b5748571b60fe9ad112715d6a51725d6e5a52a9c3af5fd36a1724cf50d862f000120b3b5748571b60fe9ad112715d6a51725d6e5a52a9c3af5fd36a1724cf50d862f20593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c1689fa69f20934cc3ede9dff4589af59c19a14a3f70000000000342b0d5cfb4e1ffc000cf99e000000d57dc73bca0753cbd47bb33f68362ac13e6daeadd57dc73bca0753cbd47bb33f68362ac13e6daeadc69a0bda7daaae481be8def95e5f347a1d00a4b430816ab3f50007333bcb40445130cd0e82139f8c68b592001cd686efc15e303206491fada6cf90af8f24a28b81a9b59ccf000141b308f737ca9e39f67b553158903198a88c516e01fb8f3001fb05a3ba8ce1dc72857b4168e33272571df7fbaf84c316dfe48217addcf6595e254216000120ba8ce1dc72857b4168e33272571df7fbaf84c316dfe48217addcf6595e25421620593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c1488164ceb25e5c05e3192511d2be4a5ac103cc5f70000000000342aca80fb4e1ffc000cf99e000000ca94dd35b74cb251457e475dd7507055eaf1b4e1ca94dd35b74cb251457e475dd7507055eaf1b4e1c69a0bda7daaae481be8def95e5f347a1d00a4b430acec7bbead86221590f132810b8262cf98c91b338927907b86bf48baa54dd1912bfc1f6fccd069052cc8c79eb9e8ed2c000162e0104ce0aafc1f06bde37c73702fe84b307f0501fb8f3001fb05a3bbfd0ac1977011267a7032641ef5487fe15a4de798faa485b156fb3b7eb0acb8000120bbfd0ac1977011267a7032641ef5487fe15a4de798faa485b156fb3b7eb0acb820593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c060d8235767cb55972a30d653eb9dd10f51b3c46ec0000000000235231c4fb4e1ffc000cf99e000000f9b93e179a0c22afd92523427341b5e0b2c2a102f9b93e179a0c22afd92523427341b5e0b2c2a102c69a0bda7daaae481be8def95e5f347a1d00a4b43095c89af86eeacfe403684306c98173c2a59198047a778787887d34ad6b0c9b787d689a7c3cd9e9dd5d103cba70f3855f0001dbbebbc52a5bae21b818e0487311041c91b2683b01fb8f3001fb05a3c11c1168dcf9479475cb1355855e30ea75c0cdda8a8f9ea80591568dd1c33ba8000120c11c1168dcf9479475cb1355855e30ea75c0cdda8a8f9ea80591568dd1c33ba820593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c040cb28bcdc1d1a970b6255a04138f84c0ebfa52b6000000000036d5cc55fb4e1ffc000cf99e000000ec040cc1866da3e55c8ae6c0f739cafabe3f5cbaec040cc1866da3e55c8ae6c0f739cafabe3f5cbac69a0bda7daaae481be8def95e5f347a1d00a4b430aa910b9552857a7712d54b468dfcbb7d9e27f26a49e06fb1f0fb00dd0f5a1bf926863c25ad03fd49c56b62065ecd06e70001fdae7cdf38811659ce9481975b326a5d07236bc501fb8f3001fb05a3d9b090cfc19caf2e27d512e69c43812a274bdf29c081d0ade4fd272ad56a5f89000120d9b090cfc19caf2e27d512e69c43812a274bdf29c081d0ade4fd272ad56a5f8920593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c0d47eb59e9a49b3794acf272f1bfff17f228291daf00000000002cf06266fb4e1ffc000cf99e0000007334f54da07d3b9e177f6e57c64f97bb0f982caf7334f54da07d3b9e177f6e57c64f97bb0f982cafc69a0bda7daaae481be8def95e5f347a1d00a4b43086108e551691da2642f37b68bcfbc5bbe9984ca51aca15ee24b6fa9b8690ed62c6ed722d091e04ef617cfc99341fd35800017034f0d3853c5351fb8e0ffd3c1daf12c51c2d8901fb8f3001fb05a3ee733db5519c987496eb3b871d5fa543ddb19db3e848f2fbb0af01585fc76af5000120ee733db5519c987496eb3b871d5fa543ddb19db3e848f2fbb0af01585fc76af520f56ac75f5801afb0fbf248e8b39db1dd43a55f1d873beb9674989c51b53d73ee0191be18196047ed60fca300e6fdca0b7bea81beac00000000000238d45dfb4e1ffc000de7c001fc000de9f801fc000f13a3000bf9547a7b4d12def0019da71e989821a60d9c915b44dc4b3f0ed26a8243afa46bada49c18da6b2a21eca01872dbfce4bf20886a004f6caaa69c1ff730b695a4757d60c472f67a7807def81ab7a52dec3bc64aa1c4188d02a4768ac3a862b404f0656ed395f1eb6470dca7bca400018355913e3791438c18b5ac50fe03784df789424101fb8f3001fb05a3f6496d3c0ac1ad94ff5e3aab2edcabc1c8ba3fbfea0ef3026e90ba7863990381000120f6496d3c0ac1ad94ff5e3aab2edcabc1c8ba3fbfea0ef3026e90ba786399038120593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c050d1611e03249023d89c1ac086036cbea392768cc0000000000340dfab6fb4e1ffc000cf99e0000006cc3fca46aae1c44ea1bab81d506e9f0a3ae1d056cc3fca46aae1c44ea1bab81d506e9f0a3ae1d05c69a0bda7daaae481be8def95e5f347a1d00a4b4308f2df81ba65db70eaab625c5fe46f0f5e52a45b25c761686db23b4f18e547cb0d161912dd187302eb6f7c4a9a666a3230001fe2d4798df3e9b41a6823bc0b3f020478e87925d01fb8f3001fb05a3fc196382366234f4645215261ca7e62f53499345ec1def69289e47c0c388dc6d000120fc196382366234f4645215261ca7e62f53499345ec1def69289e47c0c388dc6d20151b4f6fbc7351efba1dd1c36c733978a184561af7497b25b4a8a3e0afec0e7f016608134feb91cb878b26b977f1d7983a2f14452a4248000000258b0cf7fb4e1ffc000df5420001fc000df56b00c346a8ffbdcc80462cb69a6f524388a5f496fc6ec9a9263ee8c8c606c449959c48978ba70d4a097bfc86e599d56c282377dd9510ee62c55fefa553b1308d0651a04f9c243872f613901a1eeb2fa86f3e9a65168bc39941790783d9189a9a7876cedb0c6d7ff7d49fbc88a7191100011348d8f97063cf6ff602c14bf59b5ff501c8bbf401fb8f3001fb05a3ff261d2c1c76907a2ad8aeb6c5611796f03b5cbd88ae92452a4727e13f4f4ac9000120ff261d2c1c76907a2ad8aeb6c5611796f03b5cbd88ae92452a4727e13f4f4ac920593aaec65459ca9a97bd34b2657c8201ae83952d062715ba3af0d4255e54e86c0c456ce31778e3778c88a87ac36a1a8bd4aa5bdbe9000000000036bb0ee8fb4e1ffc000cf99e000000b14f661da8227a41acef9f8096df2afd2a192aafb14f661da8227a41acef9f8096df2afd2a192aafc69a0bda7daaae481be8def95e5f347a1d00a4b430967796952922dcc5208a3848ab85a787e4592df2d8ce36a29369b0b3a9576073651075039e1377873aa8c67514ad2726000167e05b1b52c7c896adf20035036fe1d30dcefc9c01fb8f3001fb05a301fb037f01fb03e8fb6978fb0190140afb07d0fb3a98fc000493e0fb3c8cfc000493e0fb0dac64fb012cfb1388fb177064fb2710fb2328fb3a98fb2328fb2710fb271032fb01f40a28321e643cfc000186a0fc000186a0fc000186a0fc000186a0fc000186a0fc000186a0fc000186a0fd00000004a817c800fd0000005d21dba000fc00989680" +}); diff --git a/packages/rs-drive-abci/tests/strategy_tests/execution.rs b/packages/rs-drive-abci/tests/strategy_tests/execution.rs index 8b6b5767ec..777dc361a2 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/execution.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/execution.rs @@ -829,8 +829,15 @@ pub(crate) fn start_chain_for_strategy( .get::(¤t_validator_quorum_hash) .expect("expected a quorum to be found"); + let platform_state = abci_application.platform.state.load(); + let protocol_version = platform_state + .current_platform_version() + .unwrap() + .protocol_version; + drop(platform_state); + // init chain - let mut init_chain_request = static_init_chain_request(&config); + let mut init_chain_request = static_init_chain_request(&config, protocol_version); init_chain_request.initial_core_height = config.abci.genesis_core_height; init_chain_request.validator_set = Some(ValidatorSetUpdate { diff --git a/packages/rs-drive-abci/tests/strategy_tests/main.rs b/packages/rs-drive-abci/tests/strategy_tests/main.rs index 98e2b518a2..2312241cc6 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/main.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/main.rs @@ -47,7 +47,6 @@ mod tests { use crate::execution::{continue_chain_for_strategy, run_chain_for_strategy}; use crate::query::QueryStrategy; use crate::strategy::{FailureStrategy, MasternodeListChangesStrategy}; - use assert_matches::assert_matches; use dashcore_rpc::dashcore::hashes::Hash; use dashcore_rpc::dashcore::BlockHash; use dashcore_rpc::json::QuorumType; @@ -87,6 +86,7 @@ mod tests { }; use dpp::identity::{Identity, KeyType, Purpose, SecurityLevel}; use dpp::state_transition::StateTransition; + use platform_version::version::v1::PROTOCOL_VERSION_1; use platform_version::version::PlatformVersion; use simple_signer::signer::SimpleSigner; use strategy_tests::transitions::create_state_transitions_for_identities; @@ -1159,6 +1159,7 @@ mod tests { let mut platform = TestPlatformBuilder::new() .with_config(config.clone()) + .with_initial_protocol_version(PROTOCOL_VERSION_1) .build_with_mock_rpc(); let outcome = run_chain_for_strategy(&mut platform, 150, strategy, config, 15, &mut None); @@ -1885,6 +1886,7 @@ mod tests { let block_count = 120; let mut platform = TestPlatformBuilder::new() .with_config(config.clone()) + .with_initial_protocol_version(PROTOCOL_VERSION_1) .build_with_mock_rpc(); let outcome = @@ -2015,6 +2017,7 @@ mod tests { let block_count = 120; let mut platform = TestPlatformBuilder::new() .with_config(config.clone()) + .with_initial_protocol_version(PROTOCOL_VERSION_1) .build_with_mock_rpc(); let outcome = diff --git a/packages/rs-drive-abci/tests/strategy_tests/patch_platform_tests.rs b/packages/rs-drive-abci/tests/strategy_tests/patch_platform_tests.rs index 2e5fd9fe26..6a68330cae 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/patch_platform_tests.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/patch_platform_tests.rs @@ -18,6 +18,7 @@ mod tests { use platform_version::version; use platform_version::version::mocks::v2_test::TEST_PROTOCOL_VERSION_2; use platform_version::version::patches::PatchFn; + use platform_version::version::v1::PROTOCOL_VERSION_1; use platform_version::version::PlatformVersion; #[test] @@ -105,6 +106,7 @@ mod tests { let mut platform = TestPlatformBuilder::new() .with_config(config.clone()) + .with_initial_protocol_version(PROTOCOL_VERSION_1) .build_with_mock_rpc(); // Run chain before the first patch diff --git a/packages/rs-drive-abci/tests/strategy_tests/upgrade_fork_tests.rs b/packages/rs-drive-abci/tests/strategy_tests/upgrade_fork_tests.rs index 928fc0a6a7..554394956b 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/upgrade_fork_tests.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/upgrade_fork_tests.rs @@ -621,7 +621,6 @@ mod tests { epoch_time_length_s, ..Default::default() }, - initial_protocol_version: PROTOCOL_VERSION_1, block_spacing_ms: epoch_time_length_s * 1000, testing_configs: PlatformTestConfig::default_minimal_verifications(), ..Default::default() @@ -629,7 +628,7 @@ mod tests { let mut platform = TestPlatformBuilder::new() .with_config(config.clone()) - .with_initial_protocol_version(INITIAL_PROTOCOL_VERSION) + .with_initial_protocol_version(PROTOCOL_VERSION_1) .build_with_mock_rpc(); let ChainExecutionOutcome { diff --git a/packages/rs-drive-abci/tests/strategy_tests/withdrawal_tests.rs b/packages/rs-drive-abci/tests/strategy_tests/withdrawal_tests.rs index ccbcae5d73..1748498709 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/withdrawal_tests.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/withdrawal_tests.rs @@ -4,7 +4,6 @@ mod tests { use crate::strategy::{ ChainExecutionOutcome, ChainExecutionParameters, NetworkStrategy, StrategyRandomness, }; - use assert_matches::assert_matches; use dashcore_rpc::dashcore_rpc_json::{AssetUnlockStatus, AssetUnlockStatusResult}; use dpp::dashcore::bls_sig_utils::BLSSignature; use dpp::dashcore::hashes::Hash; @@ -95,13 +94,13 @@ mod tests { ..Default::default() }, block_spacing_ms: hour_in_ms, - initial_protocol_version: TEST_PLATFORM_V3.protocol_version, testing_configs: PlatformTestConfig::default_minimal_verifications(), ..Default::default() }; let mut platform = TestPlatformBuilder::new() .with_config(config.clone()) + .with_initial_protocol_version(TEST_PLATFORM_V3.protocol_version) .build_with_mock_rpc(); platform @@ -776,13 +775,13 @@ mod tests { ..Default::default() }, block_spacing_ms: hour_in_ms, - initial_protocol_version: TEST_PLATFORM_V3.protocol_version, testing_configs: PlatformTestConfig::default_minimal_verifications(), ..Default::default() }; let mut platform = TestPlatformBuilder::new() .with_config(config.clone()) + .with_initial_protocol_version(TEST_PLATFORM_V3.protocol_version) .build_with_mock_rpc(); platform @@ -1144,7 +1143,6 @@ mod tests { current_validator_quorum_hash: current_quorum_hash, current_proposer_versions, end_time_ms, - withdrawals: last_block_withdrawals, identity_nonce_counter, identity_contract_nonce_counter, instant_lock_quorums, @@ -1481,12 +1479,12 @@ mod tests { ..Default::default() }, block_spacing_ms: minute_in_ms, - initial_protocol_version: TEST_PLATFORM_V3.protocol_version, testing_configs: PlatformTestConfig::default_minimal_verifications(), ..Default::default() }; let mut platform = TestPlatformBuilder::new() + .with_initial_protocol_version(TEST_PLATFORM_V3.protocol_version) .with_config(config.clone()) .build_with_mock_rpc(); @@ -1902,7 +1900,6 @@ mod tests { ..Default::default() }, block_spacing_ms: hour_in_ms, - initial_protocol_version: TEST_PLATFORM_V3.protocol_version, testing_configs: PlatformTestConfig::default_minimal_verifications(), ..Default::default() }, @@ -2037,7 +2034,6 @@ mod tests { ..Default::default() }, block_spacing_ms: hour_in_ms, - initial_protocol_version: TEST_PLATFORM_V3.protocol_version, testing_configs: PlatformTestConfig::default_minimal_verifications(), ..Default::default() }, @@ -2199,13 +2195,13 @@ mod tests { ..Default::default() }, block_spacing_ms: minute_in_ms, - initial_protocol_version: TEST_PLATFORM_V3.protocol_version, testing_configs: PlatformTestConfig::default_minimal_verifications(), ..Default::default() }; let mut platform = TestPlatformBuilder::new() .with_config(config.clone()) + .with_initial_protocol_version(TEST_PLATFORM_V3.protocol_version) .build_with_mock_rpc(); platform @@ -2598,7 +2594,6 @@ mod tests { ..Default::default() }, block_spacing_ms: hour_in_ms, - initial_protocol_version: TEST_PLATFORM_V3.protocol_version, testing_configs: PlatformTestConfig::default_minimal_verifications(), ..Default::default() }, diff --git a/packages/rs-drive-proof-verifier/Cargo.toml b/packages/rs-drive-proof-verifier/Cargo.toml index 1c68ebcc12..f46f844629 100644 --- a/packages/rs-drive-proof-verifier/Cargo.toml +++ b/packages/rs-drive-proof-verifier/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "drive-proof-verifier" -version = "1.4.0-dev.3" +version = "1.4.1" edition = "2021" rust-version.workspace = true @@ -34,7 +34,7 @@ dpp = { path = "../rs-dpp", features = [ bincode = { version = "2.0.0-rc.3", features = ["serde"], optional = true } platform-serialization-derive = { path = "../rs-platform-serialization-derive", optional = true } platform-serialization = { path = "../rs-platform-serialization", optional = true } -tenderdash-abci = { git = "https://github.com/dashpay/rs-tenderdash-abci", version = "1.2.0+1.3.0", tag = "v1.2.0+1.3.0", features = [ +tenderdash-abci = { git = "https://github.com/dashpay/rs-tenderdash-abci", version = "1.2.1", tag = "v1.2.1+1.3.0", features = [ "crypto", ], default-features = false } tracing = { version = "0.1.37" } @@ -43,5 +43,5 @@ serde_json = { version = "1.0.103", features = [ "preserve_order", ], optional = true } hex = { version = "0.4.3" } -derive_more = { version = "0.99.11" } indexmap = { version = "2.6.0" } +derive_more = { version = "1.0", features = ["from"] } diff --git a/packages/rs-drive-proof-verifier/src/error.rs b/packages/rs-drive-proof-verifier/src/error.rs index 02752a4b12..3203eb7317 100644 --- a/packages/rs-drive-proof-verifier/src/error.rs +++ b/packages/rs-drive-proof-verifier/src/error.rs @@ -106,6 +106,10 @@ pub enum ContextProviderError { /// Core Fork Error #[error("activation fork error: {0}")] ActivationForkError(String), + + /// Async error, eg. when tokio runtime fails + #[error("async error: {0}")] + AsyncError(String), } impl From for Error { diff --git a/packages/rs-drive-proof-verifier/src/proof.rs b/packages/rs-drive-proof-verifier/src/proof.rs index 4369feec7b..e615a9a8f2 100644 --- a/packages/rs-drive-proof-verifier/src/proof.rs +++ b/packages/rs-drive-proof-verifier/src/proof.rs @@ -1377,7 +1377,7 @@ impl FromProof for ContestedResources { verify_tenderdash_proof(proof, mtd, &root_hash, provider)?; let resources: ContestedResources = - items.into_iter().map(ContestedResource::Value).collect(); + items.into_iter().map(|v| ContestedResource(v)).collect(); Ok((resources.into_option(), mtd.clone(), proof.clone())) } diff --git a/packages/rs-drive-proof-verifier/src/types.rs b/packages/rs-drive-proof-verifier/src/types.rs index 89b729851e..30a004bec1 100644 --- a/packages/rs-drive-proof-verifier/src/types.rs +++ b/packages/rs-drive-proof-verifier/src/types.rs @@ -238,11 +238,8 @@ pub struct ElementFetchRequestItem(pub Element); pub type IdentityBalanceAndRevision = (u64, Revision); /// Contested resource values. -#[derive(Debug, derive_more::From, Clone, PartialEq)] -pub enum ContestedResource { - /// Generic [Value] - Value(Value), -} +#[derive(Debug, Clone, PartialEq)] +pub struct ContestedResource(pub Value); impl ContestedResource { /// Get the value. @@ -258,13 +255,9 @@ impl ContestedResource { } } -impl TryInto for ContestedResource { - type Error = crate::Error; - - fn try_into(self) -> Result { - match self { - ContestedResource::Value(value) => Ok(value), - } +impl Into for ContestedResource { + fn into(self) -> Value { + self.0 } } @@ -275,9 +268,7 @@ impl PlatformVersionEncode for ContestedResource { encoder: &mut E, _platform_version: &platform_version::PlatformVersion, ) -> Result<(), bincode::error::EncodeError> { - match self { - ContestedResource::Value(value) => value.encode(encoder), - } + self.0.encode(encoder) } } @@ -287,7 +278,7 @@ impl PlatformVersionedDecode for ContestedResource { decoder: &mut D, _platform_version: &platform_version::PlatformVersion, ) -> Result { - Ok(ContestedResource::Value(Value::decode(decoder)?)) + Ok(ContestedResource(Value::decode(decoder)?)) } } diff --git a/packages/rs-drive/Cargo.toml b/packages/rs-drive/Cargo.toml index 94938455c5..ef9f1c4570 100644 --- a/packages/rs-drive/Cargo.toml +++ b/packages/rs-drive/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "drive" description = "Dash drive built on top of GroveDB" -version = "1.4.0-dev.3" +version = "1.4.1" authors = [ "Samuel Westrich ", "Ivan Shumkov ", @@ -31,7 +31,7 @@ dpp = { path = "../rs-dpp", features = [ ], default-features = false, optional = true } thiserror = { version = "1.0.63" } tracing = { version = "0.1.37", default-features = false, features = [] } -derive_more = { version = "0.99.17" } +derive_more = { version = "1.0", features = ["from"] } hex = { version = "0.4.3" } # optional dependencies @@ -40,9 +40,10 @@ ciborium = { git = "https://github.com/qrayven/ciborium", branch = "feat-ser-nul arc-swap = { version = "1.7.0", optional = true } serde = { version = "1.0.197", features = ["derive"], optional = true } rand = { version = "0.8.4", features = ["small_rng"], optional = true } -moka = { version = "0.11.1", features = [ +moka = { version = "0.12", features = [ "future", "futures-util", + "sync", ], optional = true } bs58 = { version = "0.5.0", optional = true } base64 = { version = "0.22.1", optional = true } @@ -50,16 +51,16 @@ tempfile = { version = "3", optional = true } enum-map = { version = "2.0.3", optional = true } intmap = { version = "2.0.0", features = ["serde"], optional = true } chrono = { version = "0.4.35", optional = true } -itertools = { version = "0.11.0", optional = true } +itertools = { version = "0.13", optional = true } grovedb = { version = "2.1.0", optional = true, default-features = false } -grovedb-costs = { version = "2.1.0", optional = true } +grovedb-costs = { version = "2.1.0", optional = true } grovedb-path = { version = "2.1.0" } grovedb-storage = { version = "2.1.0", optional = true } -grovedb-version = { version = "2.1.0"} -grovedb-epoch-based-storage-flags = { version = "2.1.0"} +grovedb-version = { version = "2.1.0" } +grovedb-epoch-based-storage-flags = { version = "2.1.0" } [dev-dependencies] -criterion = "0.3.5" +criterion = "0.5" platform-version = { path = "../rs-platform-version", features = [ "mock-versions", ] } diff --git a/packages/rs-drive/src/drive/document/delete/mod.rs b/packages/rs-drive/src/drive/document/delete/mod.rs index 3f64724bfd..c2da69240b 100644 --- a/packages/rs-drive/src/drive/document/delete/mod.rs +++ b/packages/rs-drive/src/drive/document/delete/mod.rs @@ -76,10 +76,11 @@ mod tests { use dpp::tests::json_document::{json_document_to_contract, json_document_to_document}; use crate::util::test_helpers::setup::setup_drive_with_initial_state_structure; + use dpp::version::fee::FeeVersion; use dpp::version::PlatformVersion; static EPOCH_CHANGE_FEE_VERSION_TEST: Lazy = - Lazy::new(|| BTreeMap::from([(0, PlatformVersion::first().fee_version.clone())])); + Lazy::new(|| BTreeMap::from([(0, FeeVersion::first())])); #[test] fn test_add_and_remove_family_one_document_no_transaction() { diff --git a/packages/rs-drive/src/drive/document/insert/mod.rs b/packages/rs-drive/src/drive/document/insert/mod.rs index ae327e8c30..f0eb33b8a7 100644 --- a/packages/rs-drive/src/drive/document/insert/mod.rs +++ b/packages/rs-drive/src/drive/document/insert/mod.rs @@ -60,10 +60,11 @@ mod tests { use dpp::fee::default_costs::{CachedEpochIndexFeeVersions, EpochCosts}; use dpp::fee::fee_result::FeeResult; use dpp::tests::json_document::json_document_to_document; + use dpp::version::fee::FeeVersion; use dpp::version::PlatformVersion; static EPOCH_CHANGE_FEE_VERSION_TEST: Lazy = - Lazy::new(|| BTreeMap::from([(0, PlatformVersion::first().fee_version.clone())])); + Lazy::new(|| BTreeMap::from([(0, FeeVersion::first())])); #[test] fn test_add_dashpay_documents_no_transaction() { diff --git a/packages/rs-drive/src/drive/document/update/mod.rs b/packages/rs-drive/src/drive/document/update/mod.rs index e7dc236f43..fccb43e3e8 100644 --- a/packages/rs-drive/src/drive/document/update/mod.rs +++ b/packages/rs-drive/src/drive/document/update/mod.rs @@ -65,11 +65,12 @@ mod tests { use dpp::fee::fee_result::FeeResult; use dpp::platform_value; use dpp::tests::json_document::json_document_to_document; + use dpp::version::fee::FeeVersion; use once_cell::sync::Lazy; use platform_version::version::PlatformVersion; static EPOCH_CHANGE_FEE_VERSION_TEST: Lazy = - Lazy::new(|| BTreeMap::from([(0, PlatformVersion::first().fee_version.clone())])); + Lazy::new(|| BTreeMap::from([(0, FeeVersion::first())])); #[test] fn test_create_and_update_document_same_transaction() { diff --git a/packages/rs-drive/src/drive/identity/estimation_costs/for_purpose_in_key_reference_tree/v0/mod.rs b/packages/rs-drive/src/drive/identity/estimation_costs/for_purpose_in_key_reference_tree/v0/mod.rs index f7a49a2bd7..68d4852ad3 100644 --- a/packages/rs-drive/src/drive/identity/estimation_costs/for_purpose_in_key_reference_tree/v0/mod.rs +++ b/packages/rs-drive/src/drive/identity/estimation_costs/for_purpose_in_key_reference_tree/v0/mod.rs @@ -45,6 +45,7 @@ impl Drive { Purpose::TRANSFER => ApproximateElements(1), Purpose::SYSTEM => ApproximateElements(1), Purpose::VOTING => ApproximateElements(1), + Purpose::OWNER => ApproximateElements(1), }; let estimated_layer_sizes = match purpose { @@ -58,6 +59,7 @@ impl Drive { Purpose::TRANSFER => AllReference(1, KEY_REFERENCE_SIZE, None), Purpose::SYSTEM => AllReference(1, KEY_REFERENCE_SIZE, None), Purpose::VOTING => AllReference(1, KEY_REFERENCE_SIZE, None), + Purpose::OWNER => AllReference(1, KEY_REFERENCE_SIZE, None), }; // we then need to insert the identity keys layer estimated_costs_only_with_layer_info.insert( diff --git a/packages/rs-drive/src/drive/identity/key/fetch/mod.rs b/packages/rs-drive/src/drive/identity/key/fetch/mod.rs index 248e7cd904..75466736bd 100644 --- a/packages/rs-drive/src/drive/identity/key/fetch/mod.rs +++ b/packages/rs-drive/src/drive/identity/key/fetch/mod.rs @@ -691,8 +691,8 @@ impl IdentityKeysRequest { sec_btree_map.insert(security_level, CurrentKeyOfKindRequest); } let mut purpose_btree_map = BTreeMap::new(); - for purpose in 0..=Purpose::last() as u8 { - purpose_btree_map.insert(purpose, sec_btree_map.clone()); + for purpose in Purpose::searchable_purposes() { + purpose_btree_map.insert(purpose as u8, sec_btree_map.clone()); } IdentityKeysRequest { identity_id, diff --git a/packages/rs-drive/src/util/batch/drive_op_batch/withdrawals.rs b/packages/rs-drive/src/util/batch/drive_op_batch/withdrawals.rs index 2a95fc39a7..26bf6617a7 100644 --- a/packages/rs-drive/src/util/batch/drive_op_batch/withdrawals.rs +++ b/packages/rs-drive/src/util/batch/drive_op_batch/withdrawals.rs @@ -1,8 +1,7 @@ use std::collections::HashMap; use crate::drive::identity::withdrawals::paths::{ - get_withdrawal_root_path_vec, get_withdrawal_transactions_broadcasted_path, - get_withdrawal_transactions_broadcasted_path_vec, get_withdrawal_transactions_queue_path, + get_withdrawal_root_path_vec, get_withdrawal_transactions_broadcasted_path_vec, get_withdrawal_transactions_queue_path_vec, get_withdrawal_transactions_sum_tree_path_vec, WITHDRAWAL_TRANSACTIONS_NEXT_INDEX_KEY, }; diff --git a/packages/rs-drive/tests/query_tests.rs b/packages/rs-drive/tests/query_tests.rs index e7a880a02c..5c792aa873 100644 --- a/packages/rs-drive/tests/query_tests.rs +++ b/packages/rs-drive/tests/query_tests.rs @@ -75,6 +75,7 @@ use dpp::tests::json_document::json_document_to_contract; use dpp::util::cbor_serializer; use once_cell::sync::Lazy; +use dpp::version::fee::FeeVersion; use dpp::version::PlatformVersion; #[cfg(feature = "server")] @@ -2305,7 +2306,7 @@ fn test_family_person_update() { let platform_version = PlatformVersion::latest(); let epoch_change_fee_version_test: Lazy = - Lazy::new(|| BTreeMap::from([(0, PlatformVersion::first().fee_version.clone())])); + Lazy::new(|| BTreeMap::from([(0, FeeVersion::first())])); let db_transaction = drive.grove.start_transaction(); @@ -2883,7 +2884,7 @@ fn test_family_with_nulls_query() { let platform_version = PlatformVersion::latest(); let epoch_change_fee_version_test: Lazy = - Lazy::new(|| BTreeMap::from([(0, PlatformVersion::first().fee_version.clone())])); + Lazy::new(|| BTreeMap::from([(0, FeeVersion::first())])); let db_transaction = drive.grove.start_transaction(); diff --git a/packages/rs-drive/tests/query_tests_history.rs b/packages/rs-drive/tests/query_tests_history.rs index 2d609f0c2b..c14dfeca9e 100644 --- a/packages/rs-drive/tests/query_tests_history.rs +++ b/packages/rs-drive/tests/query_tests_history.rs @@ -53,6 +53,7 @@ use dpp::document::serialization_traits::{ use dpp::document::DocumentV0Getters; use dpp::fee::default_costs::CachedEpochIndexFeeVersions; use dpp::tests::json_document::json_document_to_contract; +use dpp::version::fee::FeeVersion; use dpp::version::PlatformVersion; use drive::util::batch::grovedb_op_batch::GroveDbOpBatchV0Methods; #[cfg(feature = "server")] @@ -166,7 +167,7 @@ pub fn setup( let platform_version = PlatformVersion::latest(); let epoch_change_fee_version_test: Lazy = - Lazy::new(|| BTreeMap::from([(0, PlatformVersion::first().fee_version.clone())])); + Lazy::new(|| BTreeMap::from([(0, FeeVersion::first())])); let drive = setup_drive(Some(drive_config)); @@ -260,7 +261,7 @@ fn test_query_historical() { let platform_version = PlatformVersion::latest(); let epoch_change_fee_version_test: Lazy = - Lazy::new(|| BTreeMap::from([(0, PlatformVersion::first().fee_version.clone())])); + Lazy::new(|| BTreeMap::from([(0, FeeVersion::first())])); let db_transaction = drive.grove.start_transaction(); diff --git a/packages/rs-json-schema-compatibility-validator/Cargo.toml b/packages/rs-json-schema-compatibility-validator/Cargo.toml index 80e372925d..1bf215ed99 100644 --- a/packages/rs-json-schema-compatibility-validator/Cargo.toml +++ b/packages/rs-json-schema-compatibility-validator/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "json-schema-compatibility-validator" -version = "1.4.0-dev.3" +version = "1.4.1" edition = "2021" rust-version.workspace = true authors = ["Ivan Shumkov "] [dependencies] -json-patch = "1.2.0" +json-patch = "1.4" serde_json = "1.0.115" thiserror = "1.0.64" once_cell = "1.19.0" diff --git a/packages/rs-platform-serialization-derive/Cargo.toml b/packages/rs-platform-serialization-derive/Cargo.toml index bd7b111c68..7f8296f4b4 100644 --- a/packages/rs-platform-serialization-derive/Cargo.toml +++ b/packages/rs-platform-serialization-derive/Cargo.toml @@ -2,7 +2,7 @@ name = "platform-serialization-derive" authors = ["Samuel Westrich "] description = "Bincode serialization and deserialization derivations" -version = "1.4.0-dev.3" +version = "1.4.1" edition = "2021" rust-version.workspace = true license = "MIT" @@ -12,6 +12,6 @@ proc-macro = true [dependencies] proc-macro2 = "1.0.56" -virtue = "0.0.14" -quote = "1.0.26" -syn = "2.0.15" +virtue = "0.0.17" +quote = "1.0.37" +syn = "2.0.75" diff --git a/packages/rs-platform-serialization/Cargo.toml b/packages/rs-platform-serialization/Cargo.toml index b451c8d500..b6c39cd79d 100644 --- a/packages/rs-platform-serialization/Cargo.toml +++ b/packages/rs-platform-serialization/Cargo.toml @@ -2,7 +2,7 @@ name = "platform-serialization" authors = ["Samuel Westrich "] description = "Bincode based serialization and deserialization" -version = "1.4.0-dev.3" +version = "1.4.1" edition = "2021" rust-version.workspace = true license = "MIT" diff --git a/packages/rs-platform-value-convertible/Cargo.toml b/packages/rs-platform-value-convertible/Cargo.toml index 74023ae583..ad17e9d567 100644 --- a/packages/rs-platform-value-convertible/Cargo.toml +++ b/packages/rs-platform-value-convertible/Cargo.toml @@ -2,7 +2,7 @@ name = "platform-value-convertible" authors = ["Samuel Westrich "] description = "Convertion to and from platform values" -version = "1.4.0-dev.3" +version = "1.4.1" edition = "2021" rust-version.workspace = true license = "MIT" @@ -11,5 +11,5 @@ license = "MIT" proc-macro = true [dependencies] -quote = "1.0.26" -syn = "2.0.15" +quote = "1.0.37" +syn = "2.0.75" diff --git a/packages/rs-platform-value/Cargo.toml b/packages/rs-platform-value/Cargo.toml index 59ccf1c175..15a35ffb22 100644 --- a/packages/rs-platform-value/Cargo.toml +++ b/packages/rs-platform-value/Cargo.toml @@ -2,7 +2,7 @@ name = "platform-value" authors = ["Samuel Westrich "] description = "A simple value module" -version = "1.4.0-dev.3" +version = "1.4.1" edition = "2021" rust-version.workspace = true license = "MIT" diff --git a/packages/rs-platform-value/src/string_encoding.rs b/packages/rs-platform-value/src/string_encoding.rs index c31d172839..bce2c69fbb 100644 --- a/packages/rs-platform-value/src/string_encoding.rs +++ b/packages/rs-platform-value/src/string_encoding.rs @@ -3,13 +3,27 @@ use base64; use base64::prelude::BASE64_STANDARD; use base64::Engine; use bs58; +use std::fmt; +#[derive(Debug, Copy, Clone)] pub enum Encoding { Base58, Base64, Hex, } +pub const ALL_ENCODINGS: [Encoding; 3] = [Encoding::Hex, Encoding::Base58, Encoding::Base64]; + +impl fmt::Display for Encoding { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Encoding::Base58 => write!(f, "Base58"), + Encoding::Base64 => write!(f, "Base64"), + Encoding::Hex => write!(f, "Hex"), + } + } +} + pub fn decode(encoded_value: &str, encoding: Encoding) -> Result, Error> { match encoding { Encoding::Base58 => Ok(bs58::decode(encoded_value) diff --git a/packages/rs-platform-value/src/types/identifier.rs b/packages/rs-platform-value/src/types/identifier.rs index 07bdcbd425..f2f173b7d7 100644 --- a/packages/rs-platform-value/src/types/identifier.rs +++ b/packages/rs-platform-value/src/types/identifier.rs @@ -11,7 +11,7 @@ use serde::{Deserialize, Serialize}; #[cfg(feature = "json")] use serde_json::Value as JsonValue; -use crate::string_encoding::Encoding; +use crate::string_encoding::{Encoding, ALL_ENCODINGS}; use crate::types::encoding_string_to_encoding; use crate::{string_encoding, Error, Value}; @@ -170,6 +170,29 @@ impl Identifier { Identifier::from_bytes(&vec) } + pub fn from_string_try_encodings( + encoded_value: &str, + encodings: &[Encoding], + ) -> Result { + let mut tried = vec![]; + for encoding in encodings { + if let Ok(vec) = string_encoding::decode(encoded_value, *encoding) { + if vec.len() == 32 { + return Identifier::from_bytes(&vec); + } + } + tried.push(encoding.to_string()); + } + Err(Error::StringDecodingError(format!( + "Failed to decode string with encodings [{}]", + tried.join(", ") + ))) + } + + pub fn from_string_unknown_encoding(encoded_value: &str) -> Result { + Identifier::from_string_try_encodings(encoded_value, &ALL_ENCODINGS) + } + pub fn from_string_with_encoding_string( encoded_value: &str, encoding_string: Option<&str>, diff --git a/packages/rs-platform-version/Cargo.toml b/packages/rs-platform-version/Cargo.toml index 546704554d..4113302c47 100644 --- a/packages/rs-platform-version/Cargo.toml +++ b/packages/rs-platform-version/Cargo.toml @@ -2,16 +2,16 @@ name = "platform-version" authors = ["Samuel Westrich "] description = "Versioning library for Platform" -version = "1.4.0-dev.3" +version = "1.4.1" edition = "2021" rust-version.workspace = true license = "MIT" [dependencies] thiserror = { version = "1.0.63" } -bincode = { version = "2.0.0-rc.3"} +bincode = { version = "2.0.0-rc.3" } versioned-feature-core = { git = "https://github.com/dashpay/versioned-feature-core", version = "1.0.0" } -grovedb-version = { version = "2.1.0"} +grovedb-version = { version = "2.1.0" } once_cell = "1.19.0" [features] diff --git a/packages/rs-platform-version/src/version/drive_abci_versions.rs b/packages/rs-platform-version/src/version/drive_abci_versions.rs index f7d5dda710..03ac8cad96 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions.rs @@ -77,7 +77,7 @@ pub struct DriveAbciQuerySystemVersions { #[derive(Clone, Debug, Default)] pub struct DriveAbciStructureVersions { pub platform_state_structure: FeatureVersion, - pub platform_state_for_saving_structure: FeatureVersion, + pub platform_state_for_saving_structure_default: FeatureVersion, pub state_transition_execution_context: FeatureVersion, pub commit: FeatureVersion, pub masternode: FeatureVersion, @@ -200,6 +200,7 @@ pub struct DriveAbciStateTransitionValidationVersions { pub identity_update_state_transition: DriveAbciStateTransitionValidationVersion, pub identity_top_up_state_transition: DriveAbciStateTransitionValidationVersion, pub identity_credit_withdrawal_state_transition: DriveAbciStateTransitionValidationVersion, + pub identity_credit_withdrawal_state_transition_purpose_matches_requirements: FeatureVersion, pub identity_credit_transfer_state_transition: DriveAbciStateTransitionValidationVersion, pub masternode_vote_state_transition: DriveAbciStateTransitionValidationVersion, pub contract_create_state_transition: DriveAbciStateTransitionValidationVersion, @@ -247,6 +248,7 @@ pub struct DriveAbciMasternodeIdentitiesUpdatesMethodVersions { pub get_voter_identity_key: FeatureVersion, pub get_operator_identity_keys: FeatureVersion, pub get_owner_identity_withdrawal_key: FeatureVersion, + pub get_owner_identity_owner_key: FeatureVersion, pub get_voter_identifier_from_masternode_list_item: FeatureVersion, pub get_operator_identifier_from_masternode_list_item: FeatureVersion, pub create_operator_identity: FeatureVersion, diff --git a/packages/rs-platform-version/src/version/fee/mod.rs b/packages/rs-platform-version/src/version/fee/mod.rs index 6022a89a1f..735e1b5146 100644 --- a/packages/rs-platform-version/src/version/fee/mod.rs +++ b/packages/rs-platform-version/src/version/fee/mod.rs @@ -1,9 +1,13 @@ +use crate::error::PlatformVersionError; use crate::version::fee::data_contract::FeeDataContractValidationVersion; use crate::version::fee::hashing::FeeHashingVersion; -use crate::version::fee::processing::FeeProcessingVersion; +use crate::version::fee::processing::{ + FeeProcessingVersion, FeeProcessingVersionFieldsBeforeVersion1Point4, +}; use crate::version::fee::signature::FeeSignatureVersion; use crate::version::fee::state_transition_min_fees::StateTransitionMinFees; use crate::version::fee::storage::FeeStorageVersion; +use crate::version::fee::v1::FEE_VERSION1; use crate::version::fee::vote_resolution_fund_fees::VoteResolutionFundFees; use bincode::{Decode, Encode}; @@ -16,8 +20,13 @@ pub mod storage; pub mod v1; pub mod vote_resolution_fund_fees; +pub type FeeVersionNumber = u32; + +pub const FEE_VERSIONS: &[FeeVersion] = &[FEE_VERSION1]; + #[derive(Clone, Debug, Encode, Decode, Default, PartialEq, Eq)] pub struct FeeVersion { + pub fee_version_number: FeeVersionNumber, // Permille means devise by 1000 pub uses_version_fee_multiplier_permille: Option, pub storage: FeeStorageVersion, @@ -29,137 +38,70 @@ pub struct FeeVersion { pub vote_resolution_fund_fees: VoteResolutionFundFees, } -#[cfg(test)] -mod tests { - use super::FeeVersion; - use crate::version::fee::data_contract::FeeDataContractValidationVersion; - use crate::version::fee::hashing::FeeHashingVersion; - use crate::version::fee::processing::FeeProcessingVersion; - use crate::version::fee::signature::FeeSignatureVersion; - use crate::version::fee::state_transition_min_fees::StateTransitionMinFees; - use crate::version::fee::storage::FeeStorageVersion; - use crate::version::fee::vote_resolution_fund_fees::VoteResolutionFundFees; +impl FeeVersion { + pub fn as_static(&self) -> &'static FeeVersion { + FeeVersion::get(self.fee_version_number).expect("expected fee version to exist") + } + pub fn get<'a>(version: FeeVersionNumber) -> Result<&'a Self, PlatformVersionError> { + if version > 0 { + FEE_VERSIONS.get(version as usize - 1).ok_or_else(|| { + PlatformVersionError::UnknownVersionError(format!("no fee version {version}")) + }) + } else { + Err(PlatformVersionError::UnknownVersionError(format!( + "no fee version {version}" + ))) + } + } + + pub fn get_optional<'a>(version: FeeVersionNumber) -> Option<&'a Self> { + if version > 0 { + FEE_VERSIONS.get(version as usize - 1) + } else { + None + } + } + + pub fn first<'a>() -> &'a Self { + FEE_VERSIONS + .first() + .expect("expected to have a fee version") + } - #[test] - // If this test failed, then a new field was added in FeeVersion. And the corresponding eq needs to be updated as well - fn test_fee_version_equality() { - let version1 = FeeVersion { - uses_version_fee_multiplier_permille: None, - storage: FeeStorageVersion { - storage_disk_usage_credit_per_byte: 1, - storage_processing_credit_per_byte: 2, - storage_load_credit_per_byte: 3, - non_storage_load_credit_per_byte: 4, - storage_seek_cost: 5, - }, - signature: FeeSignatureVersion { - verify_signature_ecdsa_secp256k1: 1, - verify_signature_bls12_381: 2, - verify_signature_ecdsa_hash160: 3, - verify_signature_bip13_script_hash: 4, - verify_signature_eddsa25519_hash160: 5, - }, - hashing: FeeHashingVersion { - single_sha256_base: 1, - blake3_base: 2, - sha256_ripe_md160_base: 3, - sha256_per_block: 4, - blake3_per_block: 5, - }, - processing: FeeProcessingVersion { - fetch_identity_balance_processing_cost: 1, - fetch_identity_revision_processing_cost: 2, - fetch_identity_balance_and_revision_processing_cost: 3, - fetch_identity_cost_per_look_up_key_by_id: 4, - fetch_single_identity_key_processing_cost: 5, - perform_network_threshold_signing: 6, - validate_key_structure: 7, - fetch_prefunded_specialized_balance_processing_cost: 8, - }, - data_contract: FeeDataContractValidationVersion { - document_type_base_fee: 1, - document_type_size_fee: 2, - document_type_per_property_fee: 3, - document_type_base_non_unique_index_fee: 4, - document_type_non_unique_index_per_property_fee: 5, - document_type_base_unique_index_fee: 6, - document_type_unique_index_per_property_fee: 7, - }, - state_transition_min_fees: StateTransitionMinFees { - credit_transfer: 1, - credit_withdrawal: 2, - identity_update: 3, - document_batch_sub_transition: 4, - contract_create: 5, - contract_update: 6, - masternode_vote: 7, - }, - vote_resolution_fund_fees: VoteResolutionFundFees { - contested_document_vote_resolution_fund_required_amount: 1, - contested_document_vote_resolution_unlock_fund_required_amount: 2, - contested_document_single_vote_cost: 3, - }, - }; + pub fn latest<'a>() -> &'a Self { + FEE_VERSIONS.last().expect("expected to have a fee version") + } +} - let version2 = FeeVersion { - uses_version_fee_multiplier_permille: None, - storage: FeeStorageVersion { - storage_disk_usage_credit_per_byte: 1, - storage_processing_credit_per_byte: 2, - storage_load_credit_per_byte: 3, - non_storage_load_credit_per_byte: 4, - storage_seek_cost: 5, - }, - signature: FeeSignatureVersion { - verify_signature_ecdsa_secp256k1: 1, - verify_signature_bls12_381: 2, - verify_signature_ecdsa_hash160: 3, - verify_signature_bip13_script_hash: 4, - verify_signature_eddsa25519_hash160: 5, - }, - hashing: FeeHashingVersion { - single_sha256_base: 1, - blake3_base: 2, - sha256_ripe_md160_base: 3, - sha256_per_block: 4, - blake3_per_block: 5, - }, - processing: FeeProcessingVersion { - fetch_identity_balance_processing_cost: 1, - fetch_identity_revision_processing_cost: 2, - fetch_identity_balance_and_revision_processing_cost: 3, - fetch_identity_cost_per_look_up_key_by_id: 4, - fetch_single_identity_key_processing_cost: 5, - perform_network_threshold_signing: 6, - validate_key_structure: 7, - fetch_prefunded_specialized_balance_processing_cost: 8, - }, - data_contract: FeeDataContractValidationVersion { - document_type_base_fee: 1, - document_type_size_fee: 2, - document_type_per_property_fee: 3, - document_type_base_non_unique_index_fee: 4, - document_type_non_unique_index_per_property_fee: 5, - document_type_base_unique_index_fee: 6, - document_type_unique_index_per_property_fee: 7, - }, - state_transition_min_fees: StateTransitionMinFees { - credit_transfer: 1, - credit_withdrawal: 2, - identity_update: 3, - document_batch_sub_transition: 4, - contract_create: 5, - contract_update: 6, - masternode_vote: 7, - }, - vote_resolution_fund_fees: VoteResolutionFundFees { - contested_document_vote_resolution_fund_required_amount: 1, - contested_document_vote_resolution_unlock_fund_required_amount: 2, - contested_document_single_vote_cost: 3, - }, - }; +// This is type only meant for deserialization because of an issue +// The issue was that the platform state was stored with FeeVersions in it before version 1.4 +// When we would add new fields we would be unable to deserialize +// This FeeProcessingVersionFieldsBeforeVersion4 is how things were before version 1.4 was released +#[derive(Clone, Debug, Encode, Decode, Default, PartialEq, Eq)] +pub struct FeeVersionFieldsBeforeVersion4 { + // Permille means devise by 1000 + pub uses_version_fee_multiplier_permille: Option, + pub storage: FeeStorageVersion, + pub signature: FeeSignatureVersion, + pub hashing: FeeHashingVersion, + pub processing: FeeProcessingVersionFieldsBeforeVersion1Point4, + pub data_contract: FeeDataContractValidationVersion, + pub state_transition_min_fees: StateTransitionMinFees, + pub vote_resolution_fund_fees: VoteResolutionFundFees, +} - // This assertion will check if all fields are considered in the equality comparison - assert_eq!(version1, version2, "FeeVersion equality test failed. If a field was added or removed, update the Eq implementation."); +impl From for FeeVersion { + fn from(value: FeeVersionFieldsBeforeVersion4) -> Self { + FeeVersion { + fee_version_number: 1, + uses_version_fee_multiplier_permille: value.uses_version_fee_multiplier_permille, + storage: value.storage, + signature: value.signature, + hashing: value.hashing, + processing: FeeProcessingVersion::from(value.processing), + data_contract: value.data_contract, + state_transition_min_fees: value.state_transition_min_fees, + vote_resolution_fund_fees: value.vote_resolution_fund_fees, + } } } diff --git a/packages/rs-platform-version/src/version/fee/processing/mod.rs b/packages/rs-platform-version/src/version/fee/processing/mod.rs index df88c9c0dc..a4f33696c0 100644 --- a/packages/rs-platform-version/src/version/fee/processing/mod.rs +++ b/packages/rs-platform-version/src/version/fee/processing/mod.rs @@ -1,3 +1,4 @@ +use crate::version::fee::v1::FEE_VERSION1; use bincode::{Decode, Encode}; pub mod v1; @@ -10,40 +11,42 @@ pub struct FeeProcessingVersion { pub fetch_identity_cost_per_look_up_key_by_id: u64, pub fetch_prefunded_specialized_balance_processing_cost: u64, pub fetch_single_identity_key_processing_cost: u64, - pub perform_network_threshold_signing: u64, pub validate_key_structure: u64, + pub perform_network_threshold_signing: u64, } -#[cfg(test)] -mod tests { - use super::FeeProcessingVersion; - - #[test] - // If this test failed, then a new field was added in FeeProcessingVersion. And the corresponding eq needs to be updated as well - fn test_fee_processing_version_equality() { - let version1 = FeeProcessingVersion { - fetch_identity_balance_processing_cost: 1, - fetch_identity_revision_processing_cost: 2, - fetch_identity_balance_and_revision_processing_cost: 3, - fetch_identity_cost_per_look_up_key_by_id: 4, - fetch_single_identity_key_processing_cost: 5, - perform_network_threshold_signing: 6, - validate_key_structure: 7, - fetch_prefunded_specialized_balance_processing_cost: 8, - }; - - let version2 = FeeProcessingVersion { - fetch_identity_balance_processing_cost: 1, - fetch_identity_revision_processing_cost: 2, - fetch_identity_balance_and_revision_processing_cost: 3, - fetch_identity_cost_per_look_up_key_by_id: 4, - fetch_single_identity_key_processing_cost: 5, - perform_network_threshold_signing: 6, - validate_key_structure: 7, - fetch_prefunded_specialized_balance_processing_cost: 8, - }; +// This is type only meant for deserialization because of an issue +// The issue was that the platform state was stored with FeeVersions in it before version 1.4 +// When we would add new fields we would be unable to deserialize +// This FeeProcessingVersionFieldsBeforeVersion4 is how things were before version 1.4 was released +#[derive(Clone, Debug, Encode, Decode, Default, PartialEq, Eq)] +pub struct FeeProcessingVersionFieldsBeforeVersion1Point4 { + pub fetch_identity_balance_processing_cost: u64, + pub fetch_identity_revision_processing_cost: u64, + pub fetch_identity_balance_and_revision_processing_cost: u64, + pub fetch_identity_cost_per_look_up_key_by_id: u64, + pub fetch_prefunded_specialized_balance_processing_cost: u64, + pub fetch_single_identity_key_processing_cost: u64, + pub validate_key_structure: u64, +} - // This assertion will check if all fields are considered in the equality comparison - assert_eq!(version1, version2, "FeeProcessingVersion equality test failed. If a field was added or removed, update the Eq implementation."); +impl From for FeeProcessingVersion { + fn from(old: FeeProcessingVersionFieldsBeforeVersion1Point4) -> Self { + FeeProcessingVersion { + fetch_identity_balance_processing_cost: old.fetch_identity_balance_processing_cost, + fetch_identity_revision_processing_cost: old.fetch_identity_revision_processing_cost, + fetch_identity_balance_and_revision_processing_cost: old + .fetch_identity_balance_and_revision_processing_cost, + fetch_identity_cost_per_look_up_key_by_id: old + .fetch_identity_cost_per_look_up_key_by_id, + fetch_prefunded_specialized_balance_processing_cost: old + .fetch_prefunded_specialized_balance_processing_cost, + fetch_single_identity_key_processing_cost: old + .fetch_single_identity_key_processing_cost, + validate_key_structure: old.validate_key_structure, + perform_network_threshold_signing: FEE_VERSION1 + .processing + .perform_network_threshold_signing, + } } } diff --git a/packages/rs-platform-version/src/version/fee/v1.rs b/packages/rs-platform-version/src/version/fee/v1.rs index dc5a976e11..fe43f0464c 100644 --- a/packages/rs-platform-version/src/version/fee/v1.rs +++ b/packages/rs-platform-version/src/version/fee/v1.rs @@ -8,6 +8,7 @@ use crate::version::fee::vote_resolution_fund_fees::v1::VOTE_RESOLUTION_FUND_FEE use crate::version::fee::FeeVersion; pub const FEE_VERSION1: FeeVersion = FeeVersion { + fee_version_number: 1, uses_version_fee_multiplier_permille: Some(1000), //No action storage: FEE_STORAGE_VERSION1, signature: FEE_SIGNATURE_VERSION1, diff --git a/packages/rs-platform-version/src/version/mocks/v2_test.rs b/packages/rs-platform-version/src/version/mocks/v2_test.rs index 28db2e2a7b..0edf2b425b 100644 --- a/packages/rs-platform-version/src/version/mocks/v2_test.rs +++ b/packages/rs-platform-version/src/version/mocks/v2_test.rs @@ -603,7 +603,7 @@ pub const TEST_PLATFORM_V2: PlatformVersion = PlatformVersion { drive_abci: DriveAbciVersion { structs: DriveAbciStructureVersions { platform_state_structure: 0, - platform_state_for_saving_structure: 0, + platform_state_for_saving_structure_default: 0, state_transition_execution_context: 0, commit: 0, masternode: 0, @@ -629,6 +629,7 @@ pub const TEST_PLATFORM_V2: PlatformVersion = PlatformVersion { get_voter_identity_key: 0, get_operator_identity_keys: 0, get_owner_identity_withdrawal_key: 0, + get_owner_identity_owner_key: 0, get_voter_identifier_from_masternode_list_item: 0, get_operator_identifier_from_masternode_list_item: 0, create_operator_identity: 0, @@ -769,6 +770,7 @@ pub const TEST_PLATFORM_V2: PlatformVersion = PlatformVersion { state: 0, transform_into_action: 0, }, + identity_credit_withdrawal_state_transition_purpose_matches_requirements: 0, identity_credit_transfer_state_transition: DriveAbciStateTransitionValidationVersion { basic_structure: Some(0), diff --git a/packages/rs-platform-version/src/version/mocks/v3_test.rs b/packages/rs-platform-version/src/version/mocks/v3_test.rs index aab569b63e..07e3d37ecd 100644 --- a/packages/rs-platform-version/src/version/mocks/v3_test.rs +++ b/packages/rs-platform-version/src/version/mocks/v3_test.rs @@ -603,7 +603,7 @@ pub const TEST_PLATFORM_V3: PlatformVersion = PlatformVersion { drive_abci: DriveAbciVersion { structs: DriveAbciStructureVersions { platform_state_structure: 0, - platform_state_for_saving_structure: 0, + platform_state_for_saving_structure_default: 0, state_transition_execution_context: 0, commit: 0, masternode: 0, @@ -615,7 +615,7 @@ pub const TEST_PLATFORM_V3: PlatformVersion = PlatformVersion { check_tx: 0, run_block_proposal: 0, finalize_block_proposal: 0, - consensus_params_update: 0, + consensus_params_update: 1, }, initialization: DriveAbciInitializationMethodVersions { initial_core_height_and_time: 0, @@ -629,6 +629,7 @@ pub const TEST_PLATFORM_V3: PlatformVersion = PlatformVersion { get_voter_identity_key: 0, get_operator_identity_keys: 0, get_owner_identity_withdrawal_key: 0, + get_owner_identity_owner_key: 0, get_voter_identifier_from_masternode_list_item: 0, get_operator_identifier_from_masternode_list_item: 0, create_operator_identity: 0, @@ -769,6 +770,7 @@ pub const TEST_PLATFORM_V3: PlatformVersion = PlatformVersion { state: 0, transform_into_action: 0, }, + identity_credit_withdrawal_state_transition_purpose_matches_requirements: 0, identity_credit_transfer_state_transition: DriveAbciStateTransitionValidationVersion { basic_structure: Some(0), diff --git a/packages/rs-platform-version/src/version/protocol_version.rs b/packages/rs-platform-version/src/version/protocol_version.rs index c6af2ec88c..f3d4a1871d 100644 --- a/packages/rs-platform-version/src/version/protocol_version.rs +++ b/packages/rs-platform-version/src/version/protocol_version.rs @@ -152,6 +152,10 @@ impl PlatformVersion { .expect("expected to have a platform version") } + pub fn desired<'a>() -> &'a Self { + DESIRED_PLATFORM_VERSION + } + #[cfg(feature = "mock-versions")] /// Set mock versions for testing pub fn replace_test_versions(versions: Vec) { diff --git a/packages/rs-platform-version/src/version/v1.rs b/packages/rs-platform-version/src/version/v1.rs index 8104775a5e..8369d3a30f 100644 --- a/packages/rs-platform-version/src/version/v1.rs +++ b/packages/rs-platform-version/src/version/v1.rs @@ -602,7 +602,7 @@ pub const PLATFORM_V1: PlatformVersion = PlatformVersion { drive_abci: DriveAbciVersion { structs: DriveAbciStructureVersions { platform_state_structure: 0, - platform_state_for_saving_structure: 0, + platform_state_for_saving_structure_default: 0, state_transition_execution_context: 0, commit: 0, masternode: 0, @@ -628,6 +628,7 @@ pub const PLATFORM_V1: PlatformVersion = PlatformVersion { get_voter_identity_key: 0, get_operator_identity_keys: 0, get_owner_identity_withdrawal_key: 0, + get_owner_identity_owner_key: 0, get_voter_identifier_from_masternode_list_item: 0, get_operator_identifier_from_masternode_list_item: 0, create_operator_identity: 0, @@ -768,6 +769,7 @@ pub const PLATFORM_V1: PlatformVersion = PlatformVersion { state: 0, transform_into_action: 0, }, + identity_credit_withdrawal_state_transition_purpose_matches_requirements: 0, identity_credit_transfer_state_transition: DriveAbciStateTransitionValidationVersion { basic_structure: Some(0), diff --git a/packages/rs-platform-version/src/version/v2.rs b/packages/rs-platform-version/src/version/v2.rs index 3f9931df8a..2859bb744e 100644 --- a/packages/rs-platform-version/src/version/v2.rs +++ b/packages/rs-platform-version/src/version/v2.rs @@ -602,7 +602,7 @@ pub const PLATFORM_V2: PlatformVersion = PlatformVersion { drive_abci: DriveAbciVersion { structs: DriveAbciStructureVersions { platform_state_structure: 0, - platform_state_for_saving_structure: 0, + platform_state_for_saving_structure_default: 0, state_transition_execution_context: 0, commit: 0, masternode: 0, @@ -628,6 +628,7 @@ pub const PLATFORM_V2: PlatformVersion = PlatformVersion { get_voter_identity_key: 0, get_operator_identity_keys: 0, get_owner_identity_withdrawal_key: 0, + get_owner_identity_owner_key: 0, get_voter_identifier_from_masternode_list_item: 0, get_operator_identifier_from_masternode_list_item: 0, create_operator_identity: 0, @@ -768,6 +769,7 @@ pub const PLATFORM_V2: PlatformVersion = PlatformVersion { state: 0, transform_into_action: 0, }, + identity_credit_withdrawal_state_transition_purpose_matches_requirements: 0, identity_credit_transfer_state_transition: DriveAbciStateTransitionValidationVersion { basic_structure: Some(0), diff --git a/packages/rs-platform-version/src/version/v3.rs b/packages/rs-platform-version/src/version/v3.rs index 8a57cb65a6..2c0660be1a 100644 --- a/packages/rs-platform-version/src/version/v3.rs +++ b/packages/rs-platform-version/src/version/v3.rs @@ -609,7 +609,7 @@ pub const PLATFORM_V3: PlatformVersion = PlatformVersion { drive_abci: DriveAbciVersion { structs: DriveAbciStructureVersions { platform_state_structure: 0, - platform_state_for_saving_structure: 0, + platform_state_for_saving_structure_default: 0, state_transition_execution_context: 0, commit: 0, masternode: 0, @@ -621,7 +621,8 @@ pub const PLATFORM_V3: PlatformVersion = PlatformVersion { check_tx: 0, run_block_proposal: 0, finalize_block_proposal: 0, - consensus_params_update: 0, + // Update app version if changed as well + consensus_params_update: 1, }, initialization: DriveAbciInitializationMethodVersions { initial_core_height_and_time: 0, @@ -635,6 +636,7 @@ pub const PLATFORM_V3: PlatformVersion = PlatformVersion { get_voter_identity_key: 0, get_operator_identity_keys: 0, get_owner_identity_withdrawal_key: 0, + get_owner_identity_owner_key: 0, get_voter_identifier_from_masternode_list_item: 0, get_operator_identifier_from_masternode_list_item: 0, create_operator_identity: 0, @@ -775,6 +777,7 @@ pub const PLATFORM_V3: PlatformVersion = PlatformVersion { state: 0, transform_into_action: 0, }, + identity_credit_withdrawal_state_transition_purpose_matches_requirements: 0, identity_credit_transfer_state_transition: DriveAbciStateTransitionValidationVersion { basic_structure: Some(0), diff --git a/packages/rs-platform-version/src/version/v4.rs b/packages/rs-platform-version/src/version/v4.rs index 0082ec2743..fd6429c6f6 100644 --- a/packages/rs-platform-version/src/version/v4.rs +++ b/packages/rs-platform-version/src/version/v4.rs @@ -604,7 +604,7 @@ pub const PLATFORM_V4: PlatformVersion = PlatformVersion { drive_abci: DriveAbciVersion { structs: DriveAbciStructureVersions { platform_state_structure: 0, - platform_state_for_saving_structure: 0, + platform_state_for_saving_structure_default: 0, state_transition_execution_context: 0, commit: 0, masternode: 0, @@ -616,7 +616,7 @@ pub const PLATFORM_V4: PlatformVersion = PlatformVersion { check_tx: 0, run_block_proposal: 0, finalize_block_proposal: 0, - consensus_params_update: 0, + consensus_params_update: 1, }, initialization: DriveAbciInitializationMethodVersions { initial_core_height_and_time: 0, @@ -630,15 +630,16 @@ pub const PLATFORM_V4: PlatformVersion = PlatformVersion { get_voter_identity_key: 0, get_operator_identity_keys: 0, get_owner_identity_withdrawal_key: 0, + get_owner_identity_owner_key: 0, get_voter_identifier_from_masternode_list_item: 0, get_operator_identifier_from_masternode_list_item: 0, create_operator_identity: 0, - create_owner_identity: 0, + create_owner_identity: 1, create_voter_identity: 0, disable_identity_keys: 0, update_masternode_identities: 0, update_operator_identity: 0, - update_owner_withdrawal_address: 0, + update_owner_withdrawal_address: 1, update_voter_identity: 0, }, }, @@ -770,6 +771,7 @@ pub const PLATFORM_V4: PlatformVersion = PlatformVersion { state: 0, transform_into_action: 0, }, + identity_credit_withdrawal_state_transition_purpose_matches_requirements: 0, identity_credit_transfer_state_transition: DriveAbciStateTransitionValidationVersion { basic_structure: Some(0), diff --git a/packages/rs-platform-versioning/Cargo.toml b/packages/rs-platform-versioning/Cargo.toml index 58f6935c0c..69916cbdee 100644 --- a/packages/rs-platform-versioning/Cargo.toml +++ b/packages/rs-platform-versioning/Cargo.toml @@ -2,7 +2,7 @@ name = "platform-versioning" authors = ["Samuel Westrich "] description = "Version derivation" -version = "1.4.0-dev.3" +version = "1.4.1" edition = "2021" rust-version.workspace = true license = "MIT" @@ -12,5 +12,5 @@ proc-macro = true [dependencies] proc-macro2 = "1.0.56" -quote = "1.0.26" -syn = "2.0.15" +quote = "1.0.37" +syn = "2.0.75" diff --git a/packages/rs-sdk/Cargo.toml b/packages/rs-sdk/Cargo.toml index 44f37a8d89..dcce9de6fb 100644 --- a/packages/rs-sdk/Cargo.toml +++ b/packages/rs-sdk/Cargo.toml @@ -1,9 +1,10 @@ [package] name = "dash-sdk" -version = "1.4.0-dev.3" +version = "1.4.1" edition = "2021" [dependencies] + arc-swap = { version = "1.7.1" } dpp = { path = "../rs-dpp", default-features = false, features = [ "dash-sdk-features", @@ -15,11 +16,11 @@ drive = { path = "../rs-drive", default-features = false, features = [ ] } drive-proof-verifier = { path = "../rs-drive-proof-verifier" } dapi-grpc-macros = { path = "../rs-dapi-grpc-macros" } +http = { version = "1.1" } thiserror = "1.0.64" -tokio = { version = "1.40.0", features = ["macros"] } +tokio = { version = "1.40", features = ["macros", "rt-multi-thread"] } tokio-util = { version = "0.7.12" } async-trait = { version = "0.1.83" } -http = { version = "0.2.12" } ciborium = { git = "https://github.com/qrayven/ciborium", branch = "feat-ser-null-as-undefined" } serde = { version = "1.0.197", default-features = false, features = [ "rc", @@ -30,15 +31,15 @@ hex = { version = "0.4.3" } dotenvy = { version = "0.15.7", optional = true } envy = { version = "0.4.2", optional = true } futures = { version = "0.3.30" } -derive_more = { version = "0.99.17" } +derive_more = { version = "1.0", features = ["from"] } # dashcore-rpc is only needed for core rpc; TODO remove once we have correct core rpc impl dashcore-rpc = { git = "https://github.com/dashpay/rust-dashcore-rpc", tag = "v0.15.4" } lru = { version = "0.12.3", optional = true } bip37-bloom-filter = { git = "https://github.com/dashpay/rs-bip37-bloom-filter", branch = "develop" } -pollster = { version = "0.3.0" } +zeroize = { version = "1.8", features = ["derive"] } [dev-dependencies] -tokio = { version = "1.40.0", features = ["macros", "rt-multi-thread"] } +tokio = { version = "1.40", features = ["macros", "rt-multi-thread"] } rs-dapi-client = { path = "../rs-dapi-client", features = ["mocks"] } base64 = { version = "0.22.1" } tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } @@ -56,6 +57,7 @@ test-case = { version = "3.3.1" } [features] default = ["mocks", "offline-testing"] +tokio-sleep = ["rs-dapi-client/tokio-sleep"] mocks = [ "dep:serde", @@ -69,6 +71,7 @@ mocks = [ "dep:dotenvy", "dep:envy", "dep:lru", + "zeroize/serde", ] # Run integration tests using test vectors from `tests/vectors/` instead of connecting to live Dash Platform. diff --git a/packages/rs-sdk/examples/read_contract.rs b/packages/rs-sdk/examples/read_contract.rs index ca37f1cfa7..7ac2cc333d 100644 --- a/packages/rs-sdk/examples/read_contract.rs +++ b/packages/rs-sdk/examples/read_contract.rs @@ -4,6 +4,7 @@ use clap::Parser; use dash_sdk::{mock::provider::GrpcContextProvider, platform::Fetch, Sdk, SdkBuilder}; use dpp::prelude::{DataContract, Identifier}; use rs_dapi_client::AddressList; +use zeroize::Zeroizing; #[derive(clap::Parser, Debug)] #[command(version)] @@ -22,7 +23,7 @@ pub struct Config { // Dash Core RPC password #[arg(short = 'p', long)] - pub core_password: String, + pub core_password: Zeroizing, /// Dash Platform DAPI port #[arg(short = 'd', long)] @@ -86,7 +87,7 @@ fn setup_sdk(config: &Config) -> Sdk { .expect("parse uri"); // Now, we create the Sdk with the wallet and context provider. - let mut sdk = SdkBuilder::new(AddressList::from_iter([uri])) + let sdk = SdkBuilder::new(AddressList::from_iter([uri])) .build() .expect("cannot build sdk"); diff --git a/packages/rs-sdk/src/core_client.rs b/packages/rs-sdk/src/core/dash_core_client.rs similarity index 89% rename from packages/rs-sdk/src/core_client.rs rename to packages/rs-sdk/src/core/dash_core_client.rs index e68bb6166d..d59af4207c 100644 --- a/packages/rs-sdk/src/core_client.rs +++ b/packages/rs-sdk/src/core/dash_core_client.rs @@ -14,20 +14,33 @@ use dpp::dashcore::ProTxHash; use dpp::prelude::CoreBlockHeight; use drive_proof_verifier::error::ContextProviderError; use std::{fmt::Debug, sync::Mutex}; +use zeroize::Zeroizing; /// Core RPC client that can be used to retrieve quorum keys from core. /// -/// Implements [`ContextProvider`] trait. -/// /// TODO: This is a temporary implementation, effective until we integrate SPV. -pub struct CoreClient { +pub struct LowLevelDashCoreClient { core: Mutex, server_address: String, core_user: String, + core_password: Zeroizing, core_port: u16, } -impl Debug for CoreClient { +impl Clone for LowLevelDashCoreClient { + // As Client does not implement Clone, we just create a new instance of CoreClient here. + fn clone(&self) -> Self { + LowLevelDashCoreClient::new( + &self.server_address, + self.core_port, + &self.core_user, + &self.core_password, + ) + .expect("Failed to clone CoreClient when cloning, this should not happen") + } +} + +impl Debug for LowLevelDashCoreClient { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("CoreClient") .field("server_address", &self.server_address) @@ -37,7 +50,7 @@ impl Debug for CoreClient { } } -impl CoreClient { +impl LowLevelDashCoreClient { /// Create new Dash Core client. /// /// # Arguments @@ -63,13 +76,14 @@ impl CoreClient { core: Mutex::new(core), server_address: server_address.to_string(), core_user: core_user.to_string(), + core_password: core_password.to_string().into(), core_port, }) } } // Wallet functions -impl CoreClient { +impl LowLevelDashCoreClient { /// List unspent transactions /// /// ## Arguments diff --git a/packages/rs-sdk/src/core/mod.rs b/packages/rs-sdk/src/core/mod.rs index ed7d4726cf..f642f3b26f 100644 --- a/packages/rs-sdk/src/core/mod.rs +++ b/packages/rs-sdk/src/core/mod.rs @@ -1,4 +1,8 @@ //! Dash Core SDK implementation. //! //! TODO: This is work in progress. +#[cfg(feature = "mocks")] +mod dash_core_client; mod transaction; +#[cfg(feature = "mocks")] +pub use dash_core_client::LowLevelDashCoreClient; diff --git a/packages/rs-sdk/src/lib.rs b/packages/rs-sdk/src/lib.rs index d165a211a5..1f928ab6db 100644 --- a/packages/rs-sdk/src/lib.rs +++ b/packages/rs-sdk/src/lib.rs @@ -62,8 +62,6 @@ #![allow(rustdoc::private_intra_doc_links)] pub mod core; -#[cfg(feature = "mocks")] -mod core_client; pub mod error; mod internal_cache; pub mod mock; @@ -75,7 +73,10 @@ pub use sdk::{RequestSettings, Sdk, SdkBuilder}; pub use dashcore_rpc; pub use dpp; +pub use drive; +pub use drive_proof_verifier::types as query_types; pub use rs_dapi_client as dapi_client; +pub mod sync; /// Version of the SDK pub const VERSION: &str = env!("CARGO_PKG_VERSION"); diff --git a/packages/rs-sdk/src/mock/provider.rs b/packages/rs-sdk/src/mock/provider.rs index 8c0297bf47..879c4137eb 100644 --- a/packages/rs-sdk/src/mock/provider.rs +++ b/packages/rs-sdk/src/mock/provider.rs @@ -1,13 +1,13 @@ //! Example ContextProvider that uses the Core gRPC API to fetch data from Platform. -use crate::core_client::CoreClient; +use crate::core::LowLevelDashCoreClient; use crate::platform::Fetch; +use crate::sync::block_on; use crate::{Error, Sdk}; use arc_swap::ArcSwapAny; use dpp::prelude::{CoreBlockHeight, DataContract, Identifier}; use drive_proof_verifier::error::ContextProviderError; use drive_proof_verifier::ContextProvider; -use pollster::FutureExt; use std::hash::Hash; use std::num::NonZeroUsize; use std::sync::Arc; @@ -17,7 +17,7 @@ use std::sync::Arc; /// Example [ContextProvider] used by the Sdk for testing purposes. pub struct GrpcContextProvider { /// Core client - core: CoreClient, + core: LowLevelDashCoreClient, /// [Sdk] to use when fetching data from Platform /// /// Note that if the `sdk` is `None`, the context provider will not be able to fetch data itself and will rely on @@ -62,7 +62,8 @@ impl GrpcContextProvider { data_contracts_cache_size: NonZeroUsize, quorum_public_keys_cache_size: NonZeroUsize, ) -> Result { - let core_client = CoreClient::new(core_ip, core_port, core_user, core_password)?; + let core_client = + LowLevelDashCoreClient::new(core_ip, core_port, core_user, core_password)?; Ok(Self { core: core_client, sdk: ArcSwapAny::new(Arc::new(sdk)), @@ -197,9 +198,9 @@ impl ContextProvider for GrpcContextProvider { let sdk_cloned = sdk.clone(); - let data_contract: Option = DataContract::fetch(&sdk_cloned, contract_id) - .block_on() - .map_err(|e| ContextProviderError::DataContractFailure(e.to_string()))?; + let data_contract: Option = + block_on(async move { DataContract::fetch(&sdk_cloned, contract_id).await })? + .map_err(|e| ContextProviderError::DataContractFailure(e.to_string()))?; if let Some(ref dc) = data_contract { self.data_contracts_cache.put(*data_contract_id, dc.clone()); diff --git a/packages/rs-sdk/src/mock/sdk.rs b/packages/rs-sdk/src/mock/sdk.rs index 1936acc872..bc9c392771 100644 --- a/packages/rs-sdk/src/mock/sdk.rs +++ b/packages/rs-sdk/src/mock/sdk.rs @@ -6,6 +6,7 @@ use crate::{ types::{evonode::EvoNode, identity::IdentityRequest}, DocumentQuery, Fetch, FetchMany, Query, }, + sync::block_on, Error, Sdk, }; use arc_swap::ArcSwapOption; @@ -24,7 +25,7 @@ use rs_dapi_client::{ DapiClient, DumpData, }; use std::{collections::BTreeMap, path::PathBuf, sync::Arc}; -use tokio::sync::Mutex; +use tokio::sync::{Mutex, OwnedMutexGuard}; use super::MockResponse; @@ -82,6 +83,17 @@ impl MockDashPlatformSdk { self.platform_version } + /// Load all expectations from files in a directory asynchronously. + /// + /// See [MockDashPlatformSdk::load_expectations_sync()] for more details. + #[deprecated(since = "1.4.0", note = "use load_expectations_sync")] + pub async fn load_expectations + Send + 'static>( + &mut self, + dir: P, + ) -> Result<&mut Self, Error> { + self.load_expectations_sync(dir) + } + /// Load all expectations from files in a directory. /// /// @@ -89,7 +101,7 @@ impl MockDashPlatformSdk { /// This function can be used to load expectations after the Sdk is created, or use alternative location. /// Expectation files must be prefixed with [DapiClient::DUMP_FILE_PREFIX] and /// have `.json` extension. - pub async fn load_expectations>( + pub fn load_expectations_sync>( &mut self, dir: P, ) -> Result<&mut Self, Error> { @@ -114,97 +126,80 @@ impl MockDashPlatformSdk { .map(|f| f.path()) .collect(); + let mut dapi = block_on(self.dapi.clone().lock_owned())?; + for filename in &files { let basename = filename.file_name().unwrap().to_str().unwrap(); let request_type = basename.split('_').nth(1).unwrap_or_default(); match request_type { - "DocumentQuery" => self.load_expectation::(filename).await?, + "DocumentQuery" => load_expectation::(&mut dapi, filename)?, "GetEpochsInfoRequest" => { - self.load_expectation::(filename) - .await? + load_expectation::(&mut dapi, filename)? } "GetDataContractRequest" => { - self.load_expectation::(filename) - .await? + load_expectation::(&mut dapi, filename)? } "GetDataContractsRequest" => { - self.load_expectation::(filename) - .await? + load_expectation::(&mut dapi, filename)? } "GetDataContractHistoryRequest" => { - self.load_expectation::(filename) - .await? + load_expectation::(&mut dapi, filename)? } - "IdentityRequest" => self.load_expectation::(filename).await?, + "IdentityRequest" => load_expectation::(&mut dapi, filename)?, "GetIdentityRequest" => { - self.load_expectation::(filename) - .await? + load_expectation::(&mut dapi, filename)? } "GetIdentityBalanceRequest" => { - self.load_expectation::(filename) - .await? + load_expectation::(&mut dapi, filename)? } "GetIdentityContractNonceRequest" => { - self.load_expectation::(filename) - .await? - } - "GetIdentityBalanceAndRevisionRequest" => { - self.load_expectation::(filename) - .await? + load_expectation::(&mut dapi, filename)? } + "GetIdentityBalanceAndRevisionRequest" => load_expectation::< + proto::GetIdentityBalanceAndRevisionRequest, + >(&mut dapi, filename)?, "GetIdentityKeysRequest" => { - self.load_expectation::(filename) - .await? - } - "GetProtocolVersionUpgradeStateRequest" => { - self.load_expectation::(filename) - .await? + load_expectation::(&mut dapi, filename)? } + "GetProtocolVersionUpgradeStateRequest" => load_expectation::< + proto::GetProtocolVersionUpgradeStateRequest, + >(&mut dapi, filename)?, "GetProtocolVersionUpgradeVoteStatusRequest" => { - self.load_expectation::( - filename, - ) - .await? + load_expectation::( + &mut dapi, filename, + )? } "GetContestedResourcesRequest" => { - self.load_expectation::(filename) - .await? - } - "GetContestedResourceVoteStateRequest" => { - self.load_expectation::(filename) - .await? + load_expectation::(&mut dapi, filename)? } + "GetContestedResourceVoteStateRequest" => load_expectation::< + proto::GetContestedResourceVoteStateRequest, + >(&mut dapi, filename)?, "GetContestedResourceVotersForIdentityRequest" => { - self.load_expectation::( - filename, - ) - .await? + load_expectation::( + &mut dapi, filename, + )? } "GetContestedResourceIdentityVotesRequest" => { - self.load_expectation::( - filename, - ) - .await? + load_expectation::( + &mut dapi, filename, + )? } "GetVotePollsByEndDateRequest" => { - self.load_expectation::(filename) - .await? - } - "GetPrefundedSpecializedBalanceRequest" => { - self.load_expectation::(filename) - .await? + load_expectation::(&mut dapi, filename)? } + "GetPrefundedSpecializedBalanceRequest" => load_expectation::< + proto::GetPrefundedSpecializedBalanceRequest, + >(&mut dapi, filename)?, "GetPathElementsRequest" => { - self.load_expectation::(filename) - .await? - } - "GetTotalCreditsInPlatformRequest" => { - self.load_expectation::(filename) - .await? + load_expectation::(&mut dapi, filename)? } - "EvoNode" => self.load_expectation::(filename).await?, + "GetTotalCreditsInPlatformRequest" => load_expectation::< + proto::GetTotalCreditsInPlatformRequest, + >(&mut dapi, filename)?, + "EvoNode" => load_expectation::(&mut dapi, filename)?, _ => { return Err(Error::Config(format!( "unknown request type {} in {}, missing match arm in load_expectations?", @@ -218,21 +213,6 @@ impl MockDashPlatformSdk { Ok(self) } - async fn load_expectation(&mut self, path: &PathBuf) -> Result<(), Error> { - let data = DumpData::::load(path) - .map_err(|e| { - Error::Config(format!( - "cannot load mock expectations from {}: {}", - path.display(), - e - )) - })? - .deserialize(); - - self.dapi.lock().await.expect(&data.0, &data.1)?; - Ok(()) - } - /// Expect a [Fetch] request and return provided object. /// /// This method is used to define mock expectations for [Fetch] requests. @@ -337,16 +317,16 @@ impl MockDashPlatformSdk { objects: Option, ) -> Result<&mut Self, Error> where - <>::Request as TransportRequest>::Response: Default, R: FromIterator<(K, Option)> + + MockResponse + FromProof< >::Request, Request = >::Request, Response = <>::Request as TransportRequest>::Response, - > + MockResponse - + Sync + > + Sync + Send + Default, + <>::Request as TransportRequest>::Response: Default, { let grpc_request = query.query(self.prove()).expect("query must be correct"); self.expect(grpc_request, objects).await?; @@ -434,3 +414,25 @@ impl MockDashPlatformSdk { } } } + +/// Load expectation from file and save it to `dapi_guard` mock Dapi client. +/// +/// This function is used to load expectations from files in a directory. +/// It is implemented without reference to the `MockDashPlatformSdk` object +/// to make it easier to use in async context. +fn load_expectation( + dapi_guard: &mut OwnedMutexGuard, + path: &PathBuf, +) -> Result<(), Error> { + let data = DumpData::::load(path) + .map_err(|e| { + Error::Config(format!( + "cannot load mock expectations from {}: {}", + path.display(), + e + )) + })? + .deserialize(); + dapi_guard.expect(&data.0, &data.1)?; + Ok(()) +} diff --git a/packages/rs-sdk/src/platform/transition/withdraw_from_identity.rs b/packages/rs-sdk/src/platform/transition/withdraw_from_identity.rs index db06f29a2a..1d72c86e07 100644 --- a/packages/rs-sdk/src/platform/transition/withdraw_from_identity.rs +++ b/packages/rs-sdk/src/platform/transition/withdraw_from_identity.rs @@ -3,8 +3,7 @@ use dpp::identity::accessors::IdentityGettersV0; use dpp::identity::core_script::CoreScript; use dpp::identity::signer::Signer; -use dpp::identity::Identity; -use dpp::prelude::UserFeeIncrease; +use dpp::identity::{Identity, IdentityPublicKey}; use crate::platform::transition::broadcast::BroadcastStateTransition; use crate::platform::transition::put_settings::PutSettings; @@ -19,13 +18,15 @@ use dpp::withdrawal::Pooling; #[async_trait::async_trait] pub trait WithdrawFromIdentity { /// Function to withdraw credits from an identity. Returns the final identity balance. + /// If signing_withdrawal_key_to_use is not set, we will try to use one in the signer that is + /// available for withdrawal async fn withdraw( &self, sdk: &Sdk, address: Option
, amount: u64, core_fee_per_byte: Option, - user_fee_increase: Option, + signing_withdrawal_key_to_use: Option<&IdentityPublicKey>, signer: S, settings: Option, ) -> Result; @@ -39,12 +40,13 @@ impl WithdrawFromIdentity for Identity { address: Option
, amount: u64, core_fee_per_byte: Option, - user_fee_increase: Option, + signing_withdrawal_key_to_use: Option<&IdentityPublicKey>, signer: S, settings: Option, ) -> Result { let new_identity_nonce = sdk.get_identity_nonce(self.id(), true, settings).await?; let script = address.map(|address| CoreScript::new(address.script_pubkey())); + let user_fee_increase = settings.and_then(|settings| settings.user_fee_increase); let state_transition = IdentityCreditWithdrawalTransition::try_from_identity( self, script, @@ -53,7 +55,7 @@ impl WithdrawFromIdentity for Identity { core_fee_per_byte.unwrap_or(1), user_fee_increase.unwrap_or_default(), signer, - None, + signing_withdrawal_key_to_use, PreferredKeyPurposeForSigningWithdrawal::TransferPreferred, new_identity_nonce, sdk.version(), diff --git a/packages/rs-sdk/src/platform/types/evonode.rs b/packages/rs-sdk/src/platform/types/evonode.rs index 01c0630b49..af0fee4210 100644 --- a/packages/rs-sdk/src/platform/types/evonode.rs +++ b/packages/rs-sdk/src/platform/types/evonode.rs @@ -74,7 +74,16 @@ impl TransportRequest for EvoNode { // We also create a new client to use with this request, so that the user does not need to // reconfigure SDK to use a single node. let pool = ConnectionPool::new(1); - let mut client = Self::Client::with_uri_and_settings(uri.clone(), settings, &pool); + // We create a new client with the given URI and settings + let client_result = Self::Client::with_uri_and_settings(uri.clone(), settings, &pool); + + // Handle the result manually to create a proper error response + let mut client = match client_result { + Ok(client) => client, + Err(e) => { + return async { Err(e) }.boxed(); + } + }; let mut grpc_request = GetStatusRequest { version: Some(get_status_request::Version::V0(GetStatusRequestV0 {})), } diff --git a/packages/rs-sdk/src/sdk.rs b/packages/rs-sdk/src/sdk.rs index abd02e184c..f7f938703d 100644 --- a/packages/rs-sdk/src/sdk.rs +++ b/packages/rs-sdk/src/sdk.rs @@ -7,6 +7,7 @@ use crate::mock::MockResponse; use crate::mock::{provider::GrpcContextProvider, MockDashPlatformSdk}; use crate::platform::transition::put_settings::PutSettings; use crate::platform::{Fetch, Identifier}; +use arc_swap::{ArcSwapAny, ArcSwapOption}; use dapi_grpc::mock::Mockable; use dapi_grpc::platform::v0::{Proof, ResponseMetadata}; use dpp::bincode; @@ -40,6 +41,7 @@ use std::time::{SystemTime, UNIX_EPOCH}; #[cfg(feature = "mocks")] use tokio::sync::{Mutex, MutexGuard}; use tokio_util::sync::{CancellationToken, WaitForCancellationFuture}; +use zeroize::Zeroizing; /// How many data contracts fit in the cache. pub const DEFAULT_CONTRACT_CACHE_SIZE: usize = 100; @@ -79,7 +81,6 @@ pub type LastQueryTimestamp = u64; /// ## Examples /// /// See tests/ for examples of using the SDK. -#[derive(Clone)] pub struct Sdk { /// The network that the sdk is configured for (Dash (mainnet), Testnet, Devnet, Regtest) pub network: Network, @@ -97,7 +98,7 @@ pub struct Sdk { /// ## Panics /// /// Note that setting this to None can panic. - context_provider: Option>>, + context_provider: ArcSwapOption>, /// Cancellation token; once cancelled, all pending requests should be aborted. pub(crate) cancel_token: CancellationToken, @@ -105,6 +106,20 @@ pub struct Sdk { #[cfg(feature = "mocks")] dump_dir: Option, } +impl Clone for Sdk { + fn clone(&self) -> Self { + Self { + network: self.network, + inner: self.inner.clone(), + proofs: self.proofs, + internal_cache: Arc::clone(&self.internal_cache), + context_provider: ArcSwapOption::new(self.context_provider.load_full()), + cancel_token: self.cancel_token.clone(), + #[cfg(feature = "mocks")] + dump_dir: self.dump_dir.clone(), + } + } +} impl Debug for Sdk { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -203,8 +218,7 @@ impl Sdk { O::Request: Mockable, { let provider = self - .context_provider - .as_ref() + .context_provider() .ok_or(drive_proof_verifier::Error::ContextProviderNotSet)?; match self.inner { @@ -243,8 +257,7 @@ impl Sdk { O::Request: Mockable, { let provider = self - .context_provider - .as_ref() + .context_provider() .ok_or(drive_proof_verifier::Error::ContextProviderNotSet)?; match self.inner { @@ -262,8 +275,13 @@ impl Sdk { } } } + + /// Return [ContextProvider] used by the SDK. pub fn context_provider(&self) -> Option { - self.context_provider.as_ref().map(Arc::clone) + let provider_guard = self.context_provider.load(); + let provider = provider_guard.as_ref().map(Arc::clone); + + provider } /// Returns a mutable reference to the `MockDashPlatformSdk` instance. @@ -493,9 +511,9 @@ impl Sdk { /// [ContextProvider] is used to access state information, like data contracts and quorum public keys. /// /// Note that this will overwrite any previous context provider. - pub fn set_context_provider(&mut self, context_provider: C) { + pub fn set_context_provider(&self, context_provider: C) { self.context_provider - .replace(Arc::new(Box::new(context_provider))); + .swap(Some(Arc::new(Box::new(context_provider)))); } /// Returns a future that resolves when the Sdk is cancelled (eg. shutdown was requested). @@ -568,7 +586,7 @@ pub struct SdkBuilder { core_ip: String, core_port: u16, core_user: String, - core_password: String, + core_password: Zeroizing, /// If true, request and verify proofs of the responses. proofs: bool, @@ -604,7 +622,7 @@ impl Default for SdkBuilder { network: Network::Dash, core_ip: "".to_string(), core_port: 0, - core_password: "".to_string(), + core_password: "".to_string().into(), core_user: "".to_string(), proofs: true, @@ -727,7 +745,7 @@ impl SdkBuilder { self.core_ip = ip.to_string(); self.core_port = port; self.core_user = user.to_string(); - self.core_password = password.to_string(); + self.core_password = Zeroizing::from(password.to_string()); self } @@ -772,16 +790,18 @@ impl SdkBuilder { network: self.network, inner:SdkInstance::Dapi { dapi, version:self.version }, proofs:self.proofs, - context_provider: self.context_provider.map(Arc::new), + context_provider: ArcSwapOption::new( self.context_provider.map(Arc::new)), cancel_token: self.cancel_token, #[cfg(feature = "mocks")] dump_dir: self.dump_dir, internal_cache: Default::default(), }; // if context provider is not set correctly (is None), it means we need to fallback to core wallet - if sdk.context_provider.is_none() { + if sdk.context_provider.load().is_none() { #[cfg(feature = "mocks")] if !self.core_ip.is_empty() { + tracing::warn!( + "ContextProvider not set, falling back to a mock one; use SdkBuilder::with_context_provider() to set it up"); let mut context_provider = GrpcContextProvider::new(None, &self.core_ip, self.core_port, &self.core_user, &self.core_password, self.data_contract_cache_size, self.quorum_public_keys_cache_size)?; @@ -792,15 +812,19 @@ impl SdkBuilder { // We have cyclical dependency Sdk <-> GrpcContextProvider, so we just do some // workaround using additional Arc. let context_provider= Arc::new(context_provider); - sdk.context_provider.replace(Arc::new(Box::new(context_provider.clone()))); + sdk.context_provider.swap(Some(Arc::new(Box::new(context_provider.clone())))); context_provider.set_sdk(Some(sdk.clone())); } else{ - tracing::warn!( - "Configure ContextProvider with Sdk::with_context_provider(); otherwise Sdk will fail"); + return Err(Error::Config(concat!( + "context provider is not set, configure it with SdkBuilder::with_context_provider() ", + "or configure Core access with SdkBuilder::with_core() to use mock context provider") + .to_string())); } #[cfg(not(feature = "mocks"))] - tracing::warn!( - "Configure ContextProvider with Sdk::with_context_provider(); otherwise Sdk will fail"); + return Err(Error::Config(concat!( + "context provider is not set, configure it with SdkBuilder::with_context_provider() ", + "or enable `mocks` feature to use mock context provider") + .to_string())); }; sdk @@ -831,13 +855,13 @@ impl SdkBuilder { dump_dir: self.dump_dir.clone(), proofs:self.proofs, internal_cache: Default::default(), - context_provider:Some(Arc::new(context_provider)), + context_provider:ArcSwapAny::new( Some(Arc::new(context_provider))), cancel_token: self.cancel_token, }; let mut guard = mock_sdk.try_lock().expect("mock sdk is in use by another thread and connot be reconfigured"); guard.set_sdk(sdk.clone()); if let Some(ref dump_dir) = self.dump_dir { - pollster::block_on( guard.load_expectations(dump_dir))?; + guard.load_expectations_sync(dump_dir)?; }; sdk diff --git a/packages/rs-sdk/src/sync.rs b/packages/rs-sdk/src/sync.rs new file mode 100644 index 0000000000..d3c066e8cb --- /dev/null +++ b/packages/rs-sdk/src/sync.rs @@ -0,0 +1,171 @@ +//! Handle async calls from sync code. +//! +//! This is a workaround for an issue in tokio, where you cannot call `block_on` from sync call that is called +//! inside a tokio runtime. This module spawns async futures in active tokio runtime, and retrieves the result +//! using a channel. +use drive_proof_verifier::error::ContextProviderError; +use std::{future::Future, sync::mpsc::SendError}; +use tokio::runtime::TryCurrentError; + +#[derive(Debug, thiserror::Error)] +pub enum AsyncError { + /// Not running inside tokio runtime + #[error("not running inside tokio runtime: {0}")] + NotInTokioRuntime(#[from] TryCurrentError), + + /// Cannot receive response from async function + #[error("cannot receive response from async function: {0}")] + RecvError(#[from] std::sync::mpsc::RecvError), + + /// Cannot send response from async function + #[error("cannot send response from async function: {0}")] + SendError(String), + + #[error("asynchronous call from synchronous context failed: {0}")] + #[allow(unused)] + Generic(String), +} + +impl From> for AsyncError { + fn from(error: SendError) -> Self { + Self::SendError(error.to_string()) + } +} + +impl From for ContextProviderError { + fn from(error: AsyncError) -> Self { + ContextProviderError::AsyncError(error.to_string()) + } +} + +impl From for crate::Error { + fn from(error: AsyncError) -> Self { + Self::ContextProviderError(error.into()) + } +} + +/// Blocks on the provided future and returns the result. +/// +/// This function is used to call async functions from sync code. +/// Requires the current thread to be running in a tokio runtime. +/// +/// Due to limitations of tokio runtime, we cannot use `tokio::runtime::Runtime::block_on` if we are already inside a tokio runtime. +/// This function is a workaround for that limitation. +pub fn block_on(fut: F) -> Result +where + F: Future + Send + 'static, + F::Output: Send, +{ + tracing::trace!("block_on: running async function from sync code"); + let rt = tokio::runtime::Handle::try_current()?; + let (tx, rx) = std::sync::mpsc::channel(); + tracing::trace!("block_on: Spawning worker"); + let hdl = rt.spawn(worker(fut, tx)); + tracing::trace!("block_on: Worker spawned"); + let resp = tokio::task::block_in_place(|| rx.recv())?; + + tracing::trace!("Response received"); + if !hdl.is_finished() { + tracing::debug!("async-sync worker future is not finished, aborting; this should not happen, but it's fine"); + hdl.abort(); // cleanup the worker future + } + + Ok(resp) +} + +/// Worker function that runs the provided future and sends the result back to the caller using oneshot channel. +async fn worker( + fut: F, + // response: oneshot::Sender, + response: std::sync::mpsc::Sender, +) -> Result<(), AsyncError> { + tracing::trace!("Worker start"); + let result = fut.await; + tracing::trace!("Worker async function completed, sending response"); + response.send(result)?; + tracing::trace!("Worker response sent"); + + Ok(()) +} + +#[cfg(test)] +mod test { + use super::*; + use std::future::Future; + use tokio::{ + runtime::Builder, + sync::mpsc::{self, Receiver}, + }; + + /// Test for block_on with async code that calls sync code, which then calls async code again. + /// + /// Given: An async function that calls a sync function, which then calls another async function. + /// When: The async function is executed using block_on. + /// Then: Other threads can still do some work + #[test] + fn test_block_on_nested_async_sync() { + let rt = Builder::new_multi_thread() + .worker_threads(1) // we should be good with 1 worker thread + .max_blocking_threads(1) // we should be good with 1 blocking thread + .enable_all() + .build() + .expect("Failed to create Tokio runtime"); + // we repeat this test a few times, to make sure it's stable + for _repeat in 0..5 { + // Create a Tokio runtime; we use the current thread runtime for this test. + + const MSGS: usize = 10; + let (tx, rx) = mpsc::channel::(1); + + // Spawn new worker that will just count. + let worker = async move { + for count in 0..MSGS { + tx.send(count).await.unwrap(); + } + }; + let worker_join = rt.spawn(worker); + // Define the number of levels of execution + let levels = 4; + + // Define the innermost async function + async fn innermost_async_function( + mut rx: Receiver, + ) -> Result { + for i in 0..MSGS { + let count = rx.recv().await.unwrap(); + assert_eq!(count, i); + } + + Ok(String::from("Success")) + } + + // Define the nested sync function + fn nested_sync_function(fut: F) -> Result + where + F: Future> + Send + 'static, + F::Output: Send, + { + block_on(fut)?.map_err(|e| ContextProviderError::Generic(e.to_string())) + } + + // Define the outer async function + async fn outer_async_function( + levels: usize, + rx: Receiver, + ) -> Result { + let mut result = innermost_async_function(rx).await; + for _ in 0..levels { + result = nested_sync_function(async { result }); + } + result + } + + // Run the outer async function using block_on + let result = rt.block_on(outer_async_function(levels, rx)); + + rt.block_on(worker_join).unwrap(); + // Assert the result + assert_eq!(result.unwrap(), "Success"); + } + } +} diff --git a/packages/rs-sdk/tests/fetch/config.rs b/packages/rs-sdk/tests/fetch/config.rs index e260e4f3f2..1b6efbc615 100644 --- a/packages/rs-sdk/tests/fetch/config.rs +++ b/packages/rs-sdk/tests/fetch/config.rs @@ -11,6 +11,7 @@ use dpp::{ use rs_dapi_client::AddressList; use serde::Deserialize; use std::{path::PathBuf, str::FromStr}; +use zeroize::Zeroizing; /// Existing document ID /// @@ -43,7 +44,7 @@ pub struct Config { pub core_user: String, /// Password for Dash Core RPC interface #[serde(default)] - pub core_password: String, + pub core_password: Zeroizing, /// When true, use SSL for the Dash Platform node grpc interface #[serde(default)] pub platform_ssl: bool, @@ -71,6 +72,7 @@ pub struct Config { /// ID of document of the type [`existing_document_type_name`](Config::existing_document_type_name) /// in [`existing_data_contract_id`](Config::existing_data_contract_id). #[serde(default = "Config::default_document_id")] + #[allow(unused)] pub existing_document_id: Identifier, // Hex-encoded ProTxHash of the existing HP masternode #[serde(default = "Config::default_protxhash")] diff --git a/packages/rs-sdk/tests/fetch/contested_resource.rs b/packages/rs-sdk/tests/fetch/contested_resource.rs index 676e452df2..643396d495 100644 --- a/packages/rs-sdk/tests/fetch/contested_resource.rs +++ b/packages/rs-sdk/tests/fetch/contested_resource.rs @@ -19,7 +19,6 @@ use drive::query::{ vote_polls_by_document_type_query::VotePollsByDocumentTypeQuery, }; use drive_proof_verifier::types::ContestedResource; -use std::panic::catch_unwind; /// Test that we can fetch contested resources /// @@ -105,7 +104,7 @@ async fn contested_resources_start_at_value() { for inclusive in [true, false] { // when I set start_at_value to some value, for (i, start) in all.0.iter().enumerate() { - let ContestedResource::Value(start_value) = start.clone(); + let ContestedResource(start_value) = start.clone(); let query = VotePollsByDocumentTypeQuery { start_at_value: Some((start_value, inclusive)), @@ -217,7 +216,7 @@ async fn contested_resources_limit_PLAN_656() { ); } - let ContestedResource::Value(last) = + let ContestedResource(last) = rss.0.into_iter().last().expect("last contested resource"); start_at_value = Some((last, false)); @@ -231,14 +230,14 @@ async fn contested_resources_limit_PLAN_656() { /// ## Preconditions /// /// None -#[test_case::test_case(|_q| {}, Ok("ContestedResources([Value(Text(".into()); "unmodified base query is Ok")] +#[test_case::test_case(|_q| {}, Ok("ContestedResources([ContestedResource(Text(".into()); "unmodified base query is Ok")] #[test_case::test_case(|q| q.start_index_values = vec![Value::Text("".to_string())], Ok("".into()); "index value empty string is Ok")] #[test_case::test_case(|q| q.document_type_name = "some random non-existing name".to_string(), Err(r#"code: InvalidArgument, message: "document type some random non-existing name not found"#); "non existing document type returns InvalidArgument")] #[test_case::test_case(|q| q.index_name = "nx index".to_string(), Err(r#"code: InvalidArgument, message: "index with name nx index is not the contested index"#); "non existing index returns InvalidArgument")] #[test_case::test_case(|q| q.index_name = "dashIdentityId".to_string(), Err(r#"code: InvalidArgument, message: "index with name dashIdentityId is not the contested index"#); "existing non-contested index returns InvalidArgument")] // Disabled due to bug PLAN-653 // #[test_case::test_case(|q| q.start_at_value = Some((Value::Array(vec![]), true)), Err(r#"code: InvalidArgument"#); "start_at_value wrong index type returns InvalidArgument PLAN-653")] -#[test_case::test_case(|q| q.start_index_values = vec![], Ok(r#"ContestedResources([Value(Text("dash"))])"#.into()); "start_index_values empty vec returns top-level keys")] +#[test_case::test_case(|q| q.start_index_values = vec![], Ok(r#"ContestedResources([ContestedResource(Text("dash"))])"#.into()); "start_index_values empty vec returns top-level keys")] #[test_case::test_case(|q| q.start_index_values = vec![Value::Text("".to_string())], Ok(r#"ContestedResources([])"#.into()); "start_index_values empty string returns zero results")] #[test_case::test_case(|q| { q.start_index_values = vec![ @@ -249,7 +248,7 @@ async fn contested_resources_limit_PLAN_656() { #[test_case::test_case(|q| { q.start_index_values = vec![]; q.end_index_values = vec![Value::Text(TEST_DPNS_NAME.to_string())]; -}, Ok(r#"ContestedResources([Value(Text("dash"))])"#.into()); "end_index_values one value with empty start_index_values returns 'dash'")] +}, Ok(r#"ContestedResources([ContestedResource(Text("dash"))])"#.into()); "end_index_values one value with empty start_index_values returns 'dash'")] #[test_case::test_case(|q| { q.start_index_values = vec![]; q.end_index_values = vec![Value::Text(TEST_DPNS_NAME.to_string()), Value::Text("non existing".to_string())]; @@ -304,33 +303,35 @@ async fn contested_resources_fields( tracing::debug!(?expect, "Running test case"); // handle panics to not stop other test cases from running - let unwinded = catch_unwind(|| { - { - pollster::block_on(async { - let mut query = base_query(&cfg); - query_mut_fn(&mut query); - - let (test_case_id, sdk) = - setup_sdk_for_test_case(cfg, query.clone(), "contested_resources_fields").await; - tracing::debug!(test_case_id, ?query, "Executing query"); - - ContestedResource::fetch_many(&sdk, query).await - }) - } - }); - let result = match unwinded { + let join_handle = tokio::task::spawn(async move { + let mut query = base_query(&cfg); + query_mut_fn(&mut query); + + let (test_case_id, sdk) = + setup_sdk_for_test_case(cfg, query.clone(), "contested_resources_fields").await; + tracing::debug!(test_case_id, ?query, "Executing query"); + + ContestedResource::fetch_many(&sdk, query).await + }) + .await; + let result = match join_handle { Ok(r) => r, Err(e) => { - let msg = if let Some(s) = e.downcast_ref::<&str>() { - s.to_string() - } else if let Some(s) = e.downcast_ref::() { - s.to_string() - } else { - format!("unknown panic type: {:?}", std::any::type_name_of_val(&e)) - }; + if e.is_panic() { + let e = e.into_panic(); + let msg = if let Some(s) = e.downcast_ref::<&str>() { + s.to_string() + } else if let Some(s) = e.downcast_ref::() { + s.to_string() + } else { + format!("unknown panic type: {:?}", std::any::type_name_of_val(&e)) + }; - tracing::error!("PANIC: {}", msg); - Err(Error::Generic(msg)) + tracing::error!("PANIC: {}", msg); + Err(Error::Generic(msg)) + } else { + Err(Error::Generic(format!("JoinError: {:?}", e))) + } } }; diff --git a/packages/rs-sdk/tests/fetch/contested_resource_vote_state.rs b/packages/rs-sdk/tests/fetch/contested_resource_vote_state.rs index 944feeebe2..fef6138902 100644 --- a/packages/rs-sdk/tests/fetch/contested_resource_vote_state.rs +++ b/packages/rs-sdk/tests/fetch/contested_resource_vote_state.rs @@ -276,7 +276,7 @@ async fn contested_resource_vote_states_with_limit_PLAN_674() { type MutFn = fn(&mut ContestedDocumentVotePollDriveQuery); #[test_case(|q| q.limit = Some(0), Err("limit 0 out of bounds of [1, 100]"); "limit 0")] -#[test_case(|q| q.limit = Some(u16::MAX), Err("limit 65535 out of bounds of [1, 100]"); "limit std::u16::MAX")] +#[test_case(|q| q.limit = Some(u16::MAX), Err("limit 65535 out of bounds of [1, 100]"); "limit u16::MAX")] #[test_case(|q| q.start_at = Some(([0x11; 32], true)), Ok("Contenders { winner: None, contenders: {Identifier("); "start_at does not exist should return next contenders")] #[test_case(|q| q.start_at = Some(([0xff; 32], true)), Ok("Contenders { winner: None, contenders: {}, abstain_vote_tally: None, lock_vote_tally: None }"); "start_at 0xff;32 should return zero contenders")] #[test_case(|q| q.vote_poll.document_type_name = "nx doctype".to_string(), Err(r#"code: InvalidArgument, message: "document type nx doctype not found"#); "non existing document type returns InvalidArgument")] diff --git a/packages/rs-sdk/tests/fetch/mock_fetch.rs b/packages/rs-sdk/tests/fetch/mock_fetch.rs index 056e707642..1b96614ecd 100644 --- a/packages/rs-sdk/tests/fetch/mock_fetch.rs +++ b/packages/rs-sdk/tests/fetch/mock_fetch.rs @@ -1,4 +1,4 @@ -//! This module contains tests for the mock fetch functionality. +//! Tests of mocked Fetch trait implementations. use super::common::{mock_data_contract, mock_document_type}; use dash_sdk::{ diff --git a/packages/rs-sdk/tests/vectors/check_mn_voting_prerequisities/msg_GetContestedResourceVoteStateRequest_aaaa80ce4fdfc75252132a85e6c12bea6a47c9f7bf30133713b6b5cfec3a4d57.json b/packages/rs-sdk/tests/vectors/check_mn_voting_prerequisities/msg_GetContestedResourceVoteStateRequest_aaaa80ce4fdfc75252132a85e6c12bea6a47c9f7bf30133713b6b5cfec3a4d57.json index 300e476a45..822344f493 100644 Binary files a/packages/rs-sdk/tests/vectors/check_mn_voting_prerequisities/msg_GetContestedResourceVoteStateRequest_aaaa80ce4fdfc75252132a85e6c12bea6a47c9f7bf30133713b6b5cfec3a4d57.json and b/packages/rs-sdk/tests/vectors/check_mn_voting_prerequisities/msg_GetContestedResourceVoteStateRequest_aaaa80ce4fdfc75252132a85e6c12bea6a47c9f7bf30133713b6b5cfec3a4d57.json differ diff --git a/packages/rs-sdk/tests/vectors/check_mn_voting_prerequisities/msg_GetContestedResourcesRequest_8f71462d5f438e1b12fedf94ad5799af81392b7b0cbb7e86412da37ab13aef4b.json b/packages/rs-sdk/tests/vectors/check_mn_voting_prerequisities/msg_GetContestedResourcesRequest_8f71462d5f438e1b12fedf94ad5799af81392b7b0cbb7e86412da37ab13aef4b.json index d9c45a55bb..01c11efc17 100644 Binary files a/packages/rs-sdk/tests/vectors/check_mn_voting_prerequisities/msg_GetContestedResourcesRequest_8f71462d5f438e1b12fedf94ad5799af81392b7b0cbb7e86412da37ab13aef4b.json and b/packages/rs-sdk/tests/vectors/check_mn_voting_prerequisities/msg_GetContestedResourcesRequest_8f71462d5f438e1b12fedf94ad5799af81392b7b0cbb7e86412da37ab13aef4b.json differ diff --git a/packages/rs-sdk/tests/vectors/check_mn_voting_prerequisities/msg_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json b/packages/rs-sdk/tests/vectors/check_mn_voting_prerequisities/msg_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json index 808b4f0118..b0fd7fd2be 100644 Binary files a/packages/rs-sdk/tests/vectors/check_mn_voting_prerequisities/msg_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json and b/packages/rs-sdk/tests/vectors/check_mn_voting_prerequisities/msg_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json differ diff --git a/packages/rs-sdk/tests/vectors/check_mn_voting_prerequisities/quorum_pubkey-106-41ef25a6baff2c7a3cf388c77c826c1ffa6fb229b31c0802b1808d2c85dbc248.json b/packages/rs-sdk/tests/vectors/check_mn_voting_prerequisities/quorum_pubkey-106-41ef25a6baff2c7a3cf388c77c826c1ffa6fb229b31c0802b1808d2c85dbc248.json new file mode 100644 index 0000000000..635ffb325f --- /dev/null +++ b/packages/rs-sdk/tests/vectors/check_mn_voting_prerequisities/quorum_pubkey-106-41ef25a6baff2c7a3cf388c77c826c1ffa6fb229b31c0802b1808d2c85dbc248.json @@ -0,0 +1 @@ +9192c1fc0db514525cac97f9afc0bd811b64d9cfbe81c62afdc4568238bb27e72fa397498db6a0869b4ff55be912edc3 \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/check_mn_voting_prerequisities/quorum_pubkey-106-74bc78bfed100cb1c7da3b1aeeaff1e5767efb0daf93c69cc8294ee246526a09.json b/packages/rs-sdk/tests/vectors/check_mn_voting_prerequisities/quorum_pubkey-106-74bc78bfed100cb1c7da3b1aeeaff1e5767efb0daf93c69cc8294ee246526a09.json deleted file mode 100644 index 9d31d601d5..0000000000 --- a/packages/rs-sdk/tests/vectors/check_mn_voting_prerequisities/quorum_pubkey-106-74bc78bfed100cb1c7da3b1aeeaff1e5767efb0daf93c69cc8294ee246526a09.json +++ /dev/null @@ -1 +0,0 @@ -8fdaad8ac39e23c5b9e773184f5f54523f4bc7b1ed68a66b43c011ecfe8c6f3c38b5e8bae650b2b4434f4ff9f15e7417 \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/contested_resources_fields_0760ac4854fc8db803bbcbab8709f390bd31511a05e29cd3f170b48ca6b87584/msg_GetContestedResourcesRequest_25a3f1603510228a22726e0b4c35bce08c84a0cf72b34f6a408982f7babce2c2.json b/packages/rs-sdk/tests/vectors/contested_resources_fields_0760ac4854fc8db803bbcbab8709f390bd31511a05e29cd3f170b48ca6b87584/msg_GetContestedResourcesRequest_25a3f1603510228a22726e0b4c35bce08c84a0cf72b34f6a408982f7babce2c2.json index bbfdee7b8e..d672792464 100644 Binary files a/packages/rs-sdk/tests/vectors/contested_resources_fields_0760ac4854fc8db803bbcbab8709f390bd31511a05e29cd3f170b48ca6b87584/msg_GetContestedResourcesRequest_25a3f1603510228a22726e0b4c35bce08c84a0cf72b34f6a408982f7babce2c2.json and b/packages/rs-sdk/tests/vectors/contested_resources_fields_0760ac4854fc8db803bbcbab8709f390bd31511a05e29cd3f170b48ca6b87584/msg_GetContestedResourcesRequest_25a3f1603510228a22726e0b4c35bce08c84a0cf72b34f6a408982f7babce2c2.json differ diff --git a/packages/rs-sdk/tests/vectors/contested_resources_fields_0760ac4854fc8db803bbcbab8709f390bd31511a05e29cd3f170b48ca6b87584/msg_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json b/packages/rs-sdk/tests/vectors/contested_resources_fields_0760ac4854fc8db803bbcbab8709f390bd31511a05e29cd3f170b48ca6b87584/msg_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json index 808b4f0118..b0fd7fd2be 100644 Binary files a/packages/rs-sdk/tests/vectors/contested_resources_fields_0760ac4854fc8db803bbcbab8709f390bd31511a05e29cd3f170b48ca6b87584/msg_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json and b/packages/rs-sdk/tests/vectors/contested_resources_fields_0760ac4854fc8db803bbcbab8709f390bd31511a05e29cd3f170b48ca6b87584/msg_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json differ diff --git a/packages/rs-sdk/tests/vectors/contested_resources_fields_0760ac4854fc8db803bbcbab8709f390bd31511a05e29cd3f170b48ca6b87584/quorum_pubkey-106-41ef25a6baff2c7a3cf388c77c826c1ffa6fb229b31c0802b1808d2c85dbc248.json b/packages/rs-sdk/tests/vectors/contested_resources_fields_0760ac4854fc8db803bbcbab8709f390bd31511a05e29cd3f170b48ca6b87584/quorum_pubkey-106-41ef25a6baff2c7a3cf388c77c826c1ffa6fb229b31c0802b1808d2c85dbc248.json new file mode 100644 index 0000000000..635ffb325f --- /dev/null +++ b/packages/rs-sdk/tests/vectors/contested_resources_fields_0760ac4854fc8db803bbcbab8709f390bd31511a05e29cd3f170b48ca6b87584/quorum_pubkey-106-41ef25a6baff2c7a3cf388c77c826c1ffa6fb229b31c0802b1808d2c85dbc248.json @@ -0,0 +1 @@ +9192c1fc0db514525cac97f9afc0bd811b64d9cfbe81c62afdc4568238bb27e72fa397498db6a0869b4ff55be912edc3 \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/contested_resources_fields_0760ac4854fc8db803bbcbab8709f390bd31511a05e29cd3f170b48ca6b87584/quorum_pubkey-106-74bc78bfed100cb1c7da3b1aeeaff1e5767efb0daf93c69cc8294ee246526a09.json b/packages/rs-sdk/tests/vectors/contested_resources_fields_0760ac4854fc8db803bbcbab8709f390bd31511a05e29cd3f170b48ca6b87584/quorum_pubkey-106-74bc78bfed100cb1c7da3b1aeeaff1e5767efb0daf93c69cc8294ee246526a09.json deleted file mode 100644 index 9d31d601d5..0000000000 --- a/packages/rs-sdk/tests/vectors/contested_resources_fields_0760ac4854fc8db803bbcbab8709f390bd31511a05e29cd3f170b48ca6b87584/quorum_pubkey-106-74bc78bfed100cb1c7da3b1aeeaff1e5767efb0daf93c69cc8294ee246526a09.json +++ /dev/null @@ -1 +0,0 @@ -8fdaad8ac39e23c5b9e773184f5f54523f4bc7b1ed68a66b43c011ecfe8c6f3c38b5e8bae650b2b4434f4ff9f15e7417 \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/contested_resources_fields_473cf8e4a270ced75e199e5a3e907b4df4cd66b64365d1ac77c45bcaed443a03/msg_GetContestedResourcesRequest_80ba1d11caa6442b39ab0f05e7fd84b9984fd04a4ca40a146aea81c3ea5c39ef.json b/packages/rs-sdk/tests/vectors/contested_resources_fields_473cf8e4a270ced75e199e5a3e907b4df4cd66b64365d1ac77c45bcaed443a03/msg_GetContestedResourcesRequest_80ba1d11caa6442b39ab0f05e7fd84b9984fd04a4ca40a146aea81c3ea5c39ef.json index f4c8ab177b..a95169e68c 100644 Binary files a/packages/rs-sdk/tests/vectors/contested_resources_fields_473cf8e4a270ced75e199e5a3e907b4df4cd66b64365d1ac77c45bcaed443a03/msg_GetContestedResourcesRequest_80ba1d11caa6442b39ab0f05e7fd84b9984fd04a4ca40a146aea81c3ea5c39ef.json and b/packages/rs-sdk/tests/vectors/contested_resources_fields_473cf8e4a270ced75e199e5a3e907b4df4cd66b64365d1ac77c45bcaed443a03/msg_GetContestedResourcesRequest_80ba1d11caa6442b39ab0f05e7fd84b9984fd04a4ca40a146aea81c3ea5c39ef.json differ diff --git a/packages/rs-sdk/tests/vectors/contested_resources_fields_473cf8e4a270ced75e199e5a3e907b4df4cd66b64365d1ac77c45bcaed443a03/msg_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json b/packages/rs-sdk/tests/vectors/contested_resources_fields_473cf8e4a270ced75e199e5a3e907b4df4cd66b64365d1ac77c45bcaed443a03/msg_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json index 808b4f0118..b0fd7fd2be 100644 Binary files a/packages/rs-sdk/tests/vectors/contested_resources_fields_473cf8e4a270ced75e199e5a3e907b4df4cd66b64365d1ac77c45bcaed443a03/msg_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json and b/packages/rs-sdk/tests/vectors/contested_resources_fields_473cf8e4a270ced75e199e5a3e907b4df4cd66b64365d1ac77c45bcaed443a03/msg_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json differ diff --git a/packages/rs-sdk/tests/vectors/contested_resources_fields_473cf8e4a270ced75e199e5a3e907b4df4cd66b64365d1ac77c45bcaed443a03/quorum_pubkey-106-41ef25a6baff2c7a3cf388c77c826c1ffa6fb229b31c0802b1808d2c85dbc248.json b/packages/rs-sdk/tests/vectors/contested_resources_fields_473cf8e4a270ced75e199e5a3e907b4df4cd66b64365d1ac77c45bcaed443a03/quorum_pubkey-106-41ef25a6baff2c7a3cf388c77c826c1ffa6fb229b31c0802b1808d2c85dbc248.json new file mode 100644 index 0000000000..635ffb325f --- /dev/null +++ b/packages/rs-sdk/tests/vectors/contested_resources_fields_473cf8e4a270ced75e199e5a3e907b4df4cd66b64365d1ac77c45bcaed443a03/quorum_pubkey-106-41ef25a6baff2c7a3cf388c77c826c1ffa6fb229b31c0802b1808d2c85dbc248.json @@ -0,0 +1 @@ +9192c1fc0db514525cac97f9afc0bd811b64d9cfbe81c62afdc4568238bb27e72fa397498db6a0869b4ff55be912edc3 \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/contested_resources_fields_473cf8e4a270ced75e199e5a3e907b4df4cd66b64365d1ac77c45bcaed443a03/quorum_pubkey-106-74bc78bfed100cb1c7da3b1aeeaff1e5767efb0daf93c69cc8294ee246526a09.json b/packages/rs-sdk/tests/vectors/contested_resources_fields_473cf8e4a270ced75e199e5a3e907b4df4cd66b64365d1ac77c45bcaed443a03/quorum_pubkey-106-74bc78bfed100cb1c7da3b1aeeaff1e5767efb0daf93c69cc8294ee246526a09.json deleted file mode 100644 index 9d31d601d5..0000000000 --- a/packages/rs-sdk/tests/vectors/contested_resources_fields_473cf8e4a270ced75e199e5a3e907b4df4cd66b64365d1ac77c45bcaed443a03/quorum_pubkey-106-74bc78bfed100cb1c7da3b1aeeaff1e5767efb0daf93c69cc8294ee246526a09.json +++ /dev/null @@ -1 +0,0 @@ -8fdaad8ac39e23c5b9e773184f5f54523f4bc7b1ed68a66b43c011ecfe8c6f3c38b5e8bae650b2b4434f4ff9f15e7417 \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/contested_resources_fields_948b5a301af5fc73db7fed418a4fe90f64952b4ddd6b03a7f21d029dc110af50/msg_GetContestedResourcesRequest_5396ff2dd55051d854e18e406fbbfa6b1eff43954af904bce8f123fed7515132.json b/packages/rs-sdk/tests/vectors/contested_resources_fields_948b5a301af5fc73db7fed418a4fe90f64952b4ddd6b03a7f21d029dc110af50/msg_GetContestedResourcesRequest_5396ff2dd55051d854e18e406fbbfa6b1eff43954af904bce8f123fed7515132.json index 827e98aa3b..dbc1e576a8 100644 Binary files a/packages/rs-sdk/tests/vectors/contested_resources_fields_948b5a301af5fc73db7fed418a4fe90f64952b4ddd6b03a7f21d029dc110af50/msg_GetContestedResourcesRequest_5396ff2dd55051d854e18e406fbbfa6b1eff43954af904bce8f123fed7515132.json and b/packages/rs-sdk/tests/vectors/contested_resources_fields_948b5a301af5fc73db7fed418a4fe90f64952b4ddd6b03a7f21d029dc110af50/msg_GetContestedResourcesRequest_5396ff2dd55051d854e18e406fbbfa6b1eff43954af904bce8f123fed7515132.json differ diff --git a/packages/rs-sdk/tests/vectors/contested_resources_fields_948b5a301af5fc73db7fed418a4fe90f64952b4ddd6b03a7f21d029dc110af50/msg_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json b/packages/rs-sdk/tests/vectors/contested_resources_fields_948b5a301af5fc73db7fed418a4fe90f64952b4ddd6b03a7f21d029dc110af50/msg_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json index 808b4f0118..b0fd7fd2be 100644 Binary files a/packages/rs-sdk/tests/vectors/contested_resources_fields_948b5a301af5fc73db7fed418a4fe90f64952b4ddd6b03a7f21d029dc110af50/msg_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json and b/packages/rs-sdk/tests/vectors/contested_resources_fields_948b5a301af5fc73db7fed418a4fe90f64952b4ddd6b03a7f21d029dc110af50/msg_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json differ diff --git a/packages/rs-sdk/tests/vectors/contested_resources_fields_948b5a301af5fc73db7fed418a4fe90f64952b4ddd6b03a7f21d029dc110af50/quorum_pubkey-106-41ef25a6baff2c7a3cf388c77c826c1ffa6fb229b31c0802b1808d2c85dbc248.json b/packages/rs-sdk/tests/vectors/contested_resources_fields_948b5a301af5fc73db7fed418a4fe90f64952b4ddd6b03a7f21d029dc110af50/quorum_pubkey-106-41ef25a6baff2c7a3cf388c77c826c1ffa6fb229b31c0802b1808d2c85dbc248.json new file mode 100644 index 0000000000..635ffb325f --- /dev/null +++ b/packages/rs-sdk/tests/vectors/contested_resources_fields_948b5a301af5fc73db7fed418a4fe90f64952b4ddd6b03a7f21d029dc110af50/quorum_pubkey-106-41ef25a6baff2c7a3cf388c77c826c1ffa6fb229b31c0802b1808d2c85dbc248.json @@ -0,0 +1 @@ +9192c1fc0db514525cac97f9afc0bd811b64d9cfbe81c62afdc4568238bb27e72fa397498db6a0869b4ff55be912edc3 \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/contested_resources_fields_948b5a301af5fc73db7fed418a4fe90f64952b4ddd6b03a7f21d029dc110af50/quorum_pubkey-106-74bc78bfed100cb1c7da3b1aeeaff1e5767efb0daf93c69cc8294ee246526a09.json b/packages/rs-sdk/tests/vectors/contested_resources_fields_948b5a301af5fc73db7fed418a4fe90f64952b4ddd6b03a7f21d029dc110af50/quorum_pubkey-106-74bc78bfed100cb1c7da3b1aeeaff1e5767efb0daf93c69cc8294ee246526a09.json deleted file mode 100644 index 9d31d601d5..0000000000 --- a/packages/rs-sdk/tests/vectors/contested_resources_fields_948b5a301af5fc73db7fed418a4fe90f64952b4ddd6b03a7f21d029dc110af50/quorum_pubkey-106-74bc78bfed100cb1c7da3b1aeeaff1e5767efb0daf93c69cc8294ee246526a09.json +++ /dev/null @@ -1 +0,0 @@ -8fdaad8ac39e23c5b9e773184f5f54523f4bc7b1ed68a66b43c011ecfe8c6f3c38b5e8bae650b2b4434f4ff9f15e7417 \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/contested_resources_fields_9f57b982b3e3b0286093d8b48ab27b87b22f67a172579913f2fec7a6b5ea31b7/msg_GetContestedResourcesRequest_f06ea270a508a9d9c386b8da170f67620695a23f63dc7376bd4a509e93335ce9.json b/packages/rs-sdk/tests/vectors/contested_resources_fields_9f57b982b3e3b0286093d8b48ab27b87b22f67a172579913f2fec7a6b5ea31b7/msg_GetContestedResourcesRequest_f06ea270a508a9d9c386b8da170f67620695a23f63dc7376bd4a509e93335ce9.json index df53609095..d043efe316 100644 Binary files a/packages/rs-sdk/tests/vectors/contested_resources_fields_9f57b982b3e3b0286093d8b48ab27b87b22f67a172579913f2fec7a6b5ea31b7/msg_GetContestedResourcesRequest_f06ea270a508a9d9c386b8da170f67620695a23f63dc7376bd4a509e93335ce9.json and b/packages/rs-sdk/tests/vectors/contested_resources_fields_9f57b982b3e3b0286093d8b48ab27b87b22f67a172579913f2fec7a6b5ea31b7/msg_GetContestedResourcesRequest_f06ea270a508a9d9c386b8da170f67620695a23f63dc7376bd4a509e93335ce9.json differ diff --git a/packages/rs-sdk/tests/vectors/contested_resources_fields_9f57b982b3e3b0286093d8b48ab27b87b22f67a172579913f2fec7a6b5ea31b7/msg_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json b/packages/rs-sdk/tests/vectors/contested_resources_fields_9f57b982b3e3b0286093d8b48ab27b87b22f67a172579913f2fec7a6b5ea31b7/msg_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json index 808b4f0118..b0fd7fd2be 100644 Binary files a/packages/rs-sdk/tests/vectors/contested_resources_fields_9f57b982b3e3b0286093d8b48ab27b87b22f67a172579913f2fec7a6b5ea31b7/msg_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json and b/packages/rs-sdk/tests/vectors/contested_resources_fields_9f57b982b3e3b0286093d8b48ab27b87b22f67a172579913f2fec7a6b5ea31b7/msg_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json differ diff --git a/packages/rs-sdk/tests/vectors/contested_resources_fields_9f57b982b3e3b0286093d8b48ab27b87b22f67a172579913f2fec7a6b5ea31b7/quorum_pubkey-106-41ef25a6baff2c7a3cf388c77c826c1ffa6fb229b31c0802b1808d2c85dbc248.json b/packages/rs-sdk/tests/vectors/contested_resources_fields_9f57b982b3e3b0286093d8b48ab27b87b22f67a172579913f2fec7a6b5ea31b7/quorum_pubkey-106-41ef25a6baff2c7a3cf388c77c826c1ffa6fb229b31c0802b1808d2c85dbc248.json new file mode 100644 index 0000000000..635ffb325f --- /dev/null +++ b/packages/rs-sdk/tests/vectors/contested_resources_fields_9f57b982b3e3b0286093d8b48ab27b87b22f67a172579913f2fec7a6b5ea31b7/quorum_pubkey-106-41ef25a6baff2c7a3cf388c77c826c1ffa6fb229b31c0802b1808d2c85dbc248.json @@ -0,0 +1 @@ +9192c1fc0db514525cac97f9afc0bd811b64d9cfbe81c62afdc4568238bb27e72fa397498db6a0869b4ff55be912edc3 \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/contested_resources_fields_9f57b982b3e3b0286093d8b48ab27b87b22f67a172579913f2fec7a6b5ea31b7/quorum_pubkey-106-74bc78bfed100cb1c7da3b1aeeaff1e5767efb0daf93c69cc8294ee246526a09.json b/packages/rs-sdk/tests/vectors/contested_resources_fields_9f57b982b3e3b0286093d8b48ab27b87b22f67a172579913f2fec7a6b5ea31b7/quorum_pubkey-106-74bc78bfed100cb1c7da3b1aeeaff1e5767efb0daf93c69cc8294ee246526a09.json deleted file mode 100644 index 9d31d601d5..0000000000 --- a/packages/rs-sdk/tests/vectors/contested_resources_fields_9f57b982b3e3b0286093d8b48ab27b87b22f67a172579913f2fec7a6b5ea31b7/quorum_pubkey-106-74bc78bfed100cb1c7da3b1aeeaff1e5767efb0daf93c69cc8294ee246526a09.json +++ /dev/null @@ -1 +0,0 @@ -8fdaad8ac39e23c5b9e773184f5f54523f4bc7b1ed68a66b43c011ecfe8c6f3c38b5e8bae650b2b4434f4ff9f15e7417 \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/contested_resources_fields_b7df460e812b958de6e703d8ea325df9aab3448d0409ece3f0baf1d26629e44f/msg_GetContestedResourcesRequest_c8608f7aed7bbe4ced03c9c23f1ce28a227def58e23c39e0384e0cc02fe6360b.json b/packages/rs-sdk/tests/vectors/contested_resources_fields_b7df460e812b958de6e703d8ea325df9aab3448d0409ece3f0baf1d26629e44f/msg_GetContestedResourcesRequest_c8608f7aed7bbe4ced03c9c23f1ce28a227def58e23c39e0384e0cc02fe6360b.json index b689eb3042..5d8110bf5f 100644 Binary files a/packages/rs-sdk/tests/vectors/contested_resources_fields_b7df460e812b958de6e703d8ea325df9aab3448d0409ece3f0baf1d26629e44f/msg_GetContestedResourcesRequest_c8608f7aed7bbe4ced03c9c23f1ce28a227def58e23c39e0384e0cc02fe6360b.json and b/packages/rs-sdk/tests/vectors/contested_resources_fields_b7df460e812b958de6e703d8ea325df9aab3448d0409ece3f0baf1d26629e44f/msg_GetContestedResourcesRequest_c8608f7aed7bbe4ced03c9c23f1ce28a227def58e23c39e0384e0cc02fe6360b.json differ diff --git a/packages/rs-sdk/tests/vectors/contested_resources_fields_b7df460e812b958de6e703d8ea325df9aab3448d0409ece3f0baf1d26629e44f/msg_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json b/packages/rs-sdk/tests/vectors/contested_resources_fields_b7df460e812b958de6e703d8ea325df9aab3448d0409ece3f0baf1d26629e44f/msg_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json index 808b4f0118..b0fd7fd2be 100644 Binary files a/packages/rs-sdk/tests/vectors/contested_resources_fields_b7df460e812b958de6e703d8ea325df9aab3448d0409ece3f0baf1d26629e44f/msg_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json and b/packages/rs-sdk/tests/vectors/contested_resources_fields_b7df460e812b958de6e703d8ea325df9aab3448d0409ece3f0baf1d26629e44f/msg_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json differ diff --git a/packages/rs-sdk/tests/vectors/contested_resources_fields_b7df460e812b958de6e703d8ea325df9aab3448d0409ece3f0baf1d26629e44f/quorum_pubkey-106-41ef25a6baff2c7a3cf388c77c826c1ffa6fb229b31c0802b1808d2c85dbc248.json b/packages/rs-sdk/tests/vectors/contested_resources_fields_b7df460e812b958de6e703d8ea325df9aab3448d0409ece3f0baf1d26629e44f/quorum_pubkey-106-41ef25a6baff2c7a3cf388c77c826c1ffa6fb229b31c0802b1808d2c85dbc248.json new file mode 100644 index 0000000000..635ffb325f --- /dev/null +++ b/packages/rs-sdk/tests/vectors/contested_resources_fields_b7df460e812b958de6e703d8ea325df9aab3448d0409ece3f0baf1d26629e44f/quorum_pubkey-106-41ef25a6baff2c7a3cf388c77c826c1ffa6fb229b31c0802b1808d2c85dbc248.json @@ -0,0 +1 @@ +9192c1fc0db514525cac97f9afc0bd811b64d9cfbe81c62afdc4568238bb27e72fa397498db6a0869b4ff55be912edc3 \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/contested_resources_fields_b7df460e812b958de6e703d8ea325df9aab3448d0409ece3f0baf1d26629e44f/quorum_pubkey-106-74bc78bfed100cb1c7da3b1aeeaff1e5767efb0daf93c69cc8294ee246526a09.json b/packages/rs-sdk/tests/vectors/contested_resources_fields_b7df460e812b958de6e703d8ea325df9aab3448d0409ece3f0baf1d26629e44f/quorum_pubkey-106-74bc78bfed100cb1c7da3b1aeeaff1e5767efb0daf93c69cc8294ee246526a09.json deleted file mode 100644 index 9d31d601d5..0000000000 --- a/packages/rs-sdk/tests/vectors/contested_resources_fields_b7df460e812b958de6e703d8ea325df9aab3448d0409ece3f0baf1d26629e44f/quorum_pubkey-106-74bc78bfed100cb1c7da3b1aeeaff1e5767efb0daf93c69cc8294ee246526a09.json +++ /dev/null @@ -1 +0,0 @@ -8fdaad8ac39e23c5b9e773184f5f54523f4bc7b1ed68a66b43c011ecfe8c6f3c38b5e8bae650b2b4434f4ff9f15e7417 \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/contested_resources_fields_ccb199c48ee58a8bb98742b964cba7bda3b4469b740201d2628f15f926f39347/msg_GetContestedResourcesRequest_7dd3b1061a019dac5fa1f385b8bd5387b9cca48a3062a4db8bf0341a839f2bae.json b/packages/rs-sdk/tests/vectors/contested_resources_fields_ccb199c48ee58a8bb98742b964cba7bda3b4469b740201d2628f15f926f39347/msg_GetContestedResourcesRequest_7dd3b1061a019dac5fa1f385b8bd5387b9cca48a3062a4db8bf0341a839f2bae.json index 4f9cc1a381..73a6e5dbf6 100644 Binary files a/packages/rs-sdk/tests/vectors/contested_resources_fields_ccb199c48ee58a8bb98742b964cba7bda3b4469b740201d2628f15f926f39347/msg_GetContestedResourcesRequest_7dd3b1061a019dac5fa1f385b8bd5387b9cca48a3062a4db8bf0341a839f2bae.json and b/packages/rs-sdk/tests/vectors/contested_resources_fields_ccb199c48ee58a8bb98742b964cba7bda3b4469b740201d2628f15f926f39347/msg_GetContestedResourcesRequest_7dd3b1061a019dac5fa1f385b8bd5387b9cca48a3062a4db8bf0341a839f2bae.json differ diff --git a/packages/rs-sdk/tests/vectors/contested_resources_fields_ccb199c48ee58a8bb98742b964cba7bda3b4469b740201d2628f15f926f39347/msg_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json b/packages/rs-sdk/tests/vectors/contested_resources_fields_ccb199c48ee58a8bb98742b964cba7bda3b4469b740201d2628f15f926f39347/msg_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json index 808b4f0118..b0fd7fd2be 100644 Binary files a/packages/rs-sdk/tests/vectors/contested_resources_fields_ccb199c48ee58a8bb98742b964cba7bda3b4469b740201d2628f15f926f39347/msg_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json and b/packages/rs-sdk/tests/vectors/contested_resources_fields_ccb199c48ee58a8bb98742b964cba7bda3b4469b740201d2628f15f926f39347/msg_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json differ diff --git a/packages/rs-sdk/tests/vectors/contested_resources_fields_ccb199c48ee58a8bb98742b964cba7bda3b4469b740201d2628f15f926f39347/quorum_pubkey-106-41ef25a6baff2c7a3cf388c77c826c1ffa6fb229b31c0802b1808d2c85dbc248.json b/packages/rs-sdk/tests/vectors/contested_resources_fields_ccb199c48ee58a8bb98742b964cba7bda3b4469b740201d2628f15f926f39347/quorum_pubkey-106-41ef25a6baff2c7a3cf388c77c826c1ffa6fb229b31c0802b1808d2c85dbc248.json new file mode 100644 index 0000000000..635ffb325f --- /dev/null +++ b/packages/rs-sdk/tests/vectors/contested_resources_fields_ccb199c48ee58a8bb98742b964cba7bda3b4469b740201d2628f15f926f39347/quorum_pubkey-106-41ef25a6baff2c7a3cf388c77c826c1ffa6fb229b31c0802b1808d2c85dbc248.json @@ -0,0 +1 @@ +9192c1fc0db514525cac97f9afc0bd811b64d9cfbe81c62afdc4568238bb27e72fa397498db6a0869b4ff55be912edc3 \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/contested_resources_fields_ccb199c48ee58a8bb98742b964cba7bda3b4469b740201d2628f15f926f39347/quorum_pubkey-106-74bc78bfed100cb1c7da3b1aeeaff1e5767efb0daf93c69cc8294ee246526a09.json b/packages/rs-sdk/tests/vectors/contested_resources_fields_ccb199c48ee58a8bb98742b964cba7bda3b4469b740201d2628f15f926f39347/quorum_pubkey-106-74bc78bfed100cb1c7da3b1aeeaff1e5767efb0daf93c69cc8294ee246526a09.json deleted file mode 100644 index 9d31d601d5..0000000000 --- a/packages/rs-sdk/tests/vectors/contested_resources_fields_ccb199c48ee58a8bb98742b964cba7bda3b4469b740201d2628f15f926f39347/quorum_pubkey-106-74bc78bfed100cb1c7da3b1aeeaff1e5767efb0daf93c69cc8294ee246526a09.json +++ /dev/null @@ -1 +0,0 @@ -8fdaad8ac39e23c5b9e773184f5f54523f4bc7b1ed68a66b43c011ecfe8c6f3c38b5e8bae650b2b4434f4ff9f15e7417 \ No newline at end of file diff --git a/packages/simple-signer/Cargo.toml b/packages/simple-signer/Cargo.toml index 7e5994c015..aaa449c293 100644 --- a/packages/simple-signer/Cargo.toml +++ b/packages/simple-signer/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "simple-signer" -version = "1.4.0-dev.3" +version = "1.4.1" edition = "2021" rust-version.workspace = true diff --git a/packages/strategy-tests/Cargo.toml b/packages/strategy-tests/Cargo.toml index ecb274b11f..437d73457c 100644 --- a/packages/strategy-tests/Cargo.toml +++ b/packages/strategy-tests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "strategy-tests" -version = "1.4.0-dev.3" +version = "1.4.1" authors = [ "Samuel Westrich ", "Ivan Shumkov ", diff --git a/packages/wallet-lib/package.json b/packages/wallet-lib/package.json index 6584ecdded..9536e860ec 100644 --- a/packages/wallet-lib/package.json +++ b/packages/wallet-lib/package.json @@ -1,6 +1,6 @@ { "name": "@dashevo/wallet-lib", - "version": "8.4.0-dev.3", + "version": "8.4.1", "description": "Light wallet library for Dash", "main": "src/index.js", "unpkg": "dist/wallet-lib.min.js", @@ -46,7 +46,7 @@ "homepage": "https://github.com/dashevo/wallet-lib#readme", "dependencies": { "@dashevo/dapi-client": "workspace:*", - "@dashevo/dashcore-lib": "~0.21.3", + "@dashevo/dashcore-lib": "~0.22.0", "@dashevo/grpc-common": "workspace:*", "@dashevo/wasm-dpp": "workspace:*", "@yarnpkg/pnpify": "^4.0.0-rc.42", diff --git a/packages/wasm-dpp/Cargo.toml b/packages/wasm-dpp/Cargo.toml index 59a1163850..e9bc972494 100644 --- a/packages/wasm-dpp/Cargo.toml +++ b/packages/wasm-dpp/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasm-dpp" -version = "1.4.0-dev.3" +version = "1.4.1" edition = "2021" rust-version.workspace = true authors = ["Anton Suprunchuk "] @@ -41,10 +41,10 @@ dpp = { path = "../rs-dpp", default-features = false, features = [ "document-value-conversion", "document-json-conversion", ] } -itertools = { version = "0.10.5" } +itertools = { version = "0.13" } log = { version = "0.4.6" } wasm-logger = { version = "0.2.0" } -num_enum = "0.5.7" +num_enum = "0.7" hex = { version = "0.4" } paste = "1.0.14" anyhow = { version = "1.0.75" } diff --git a/packages/wasm-dpp/package.json b/packages/wasm-dpp/package.json index f1a4f2dd11..7821b424df 100644 --- a/packages/wasm-dpp/package.json +++ b/packages/wasm-dpp/package.json @@ -1,6 +1,6 @@ { "name": "@dashevo/wasm-dpp", - "version": "1.4.0-dev.3", + "version": "1.4.1", "description": "The JavaScript implementation of the Dash Platform Protocol", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -43,7 +43,7 @@ "@babel/cli": "^7.23.0", "@babel/core": "^7.23.3", "@babel/preset-env": "^7.23.3", - "@dashevo/dashcore-lib": "~0.21.3", + "@dashevo/dashcore-lib": "~0.22.0", "@dashevo/dpns-contract": "workspace:*", "@types/bs58": "^4.0.1", "@types/node": "^14.6.0", diff --git a/packages/wasm-dpp/src/errors/consensus/consensus_error.rs b/packages/wasm-dpp/src/errors/consensus/consensus_error.rs index 642dce93fc..627b65a267 100644 --- a/packages/wasm-dpp/src/errors/consensus/consensus_error.rs +++ b/packages/wasm-dpp/src/errors/consensus/consensus_error.rs @@ -63,13 +63,14 @@ use dpp::consensus::state::data_trigger::DataTriggerError::{ use wasm_bindgen::{JsError, JsValue}; use dpp::consensus::basic::data_contract::{ContestedUniqueIndexOnMutableDocumentTypeError, ContestedUniqueIndexWithUniqueIndexError, InvalidDocumentTypeRequiredSecurityLevelError, UnknownDocumentCreationRestrictionModeError, UnknownSecurityLevelError, UnknownStorageKeyRequirementsError, UnknownTradeModeError, UnknownTransferableTypeError}; use dpp::consensus::basic::document::{ContestedDocumentsTemporarilyNotAllowedError, DocumentCreationNotAllowedError, DocumentFieldMaxSizeExceededError, MaxDocumentsTransitionsExceededError, MissingPositionsInDocumentTypePropertiesError}; -use dpp::consensus::basic::identity::{DataContractBoundsNotPresentError, DisablingKeyIdAlsoBeingAddedInSameTransitionError, InvalidIdentityCreditWithdrawalTransitionAmountError, InvalidIdentityUpdateTransitionDisableKeysError, InvalidIdentityUpdateTransitionEmptyError, TooManyMasterPublicKeyError}; +use dpp::consensus::basic::identity::{DataContractBoundsNotPresentError, DisablingKeyIdAlsoBeingAddedInSameTransitionError, InvalidIdentityCreditWithdrawalTransitionAmountError, InvalidIdentityUpdateTransitionDisableKeysError, InvalidIdentityUpdateTransitionEmptyError, TooManyMasterPublicKeyError, WithdrawalOutputScriptNotAllowedWhenSigningWithOwnerKeyError}; use dpp::consensus::basic::overflow_error::OverflowError; use dpp::consensus::state::data_contract::document_type_update_error::DocumentTypeUpdateError; use dpp::consensus::state::document::document_contest_currently_locked_error::DocumentContestCurrentlyLockedError; use dpp::consensus::state::document::document_contest_document_with_same_id_already_present_error::DocumentContestDocumentWithSameIdAlreadyPresentError; use dpp::consensus::state::document::document_contest_identity_already_contestant::DocumentContestIdentityAlreadyContestantError; use dpp::consensus::state::document::document_contest_not_joinable_error::DocumentContestNotJoinableError; +use dpp::consensus::state::document::document_contest_not_paid_for_error::DocumentContestNotPaidForError; use dpp::consensus::state::document::document_incorrect_purchase_price_error::DocumentIncorrectPurchasePriceError; use dpp::consensus::state::document::document_not_for_sale_error::DocumentNotForSaleError; use dpp::consensus::state::identity::identity_public_key_already_exists_for_unique_contract_bounds_error::IdentityPublicKeyAlreadyExistsForUniqueContractBoundsError; @@ -304,6 +305,9 @@ pub fn from_state_error(state_error: &StateError) -> JsValue { StateError::NoTransferKeyForCoreWithdrawalAvailableError(e) => { generic_consensus_error!(NoTransferKeyForCoreWithdrawalAvailableError, e).into() } + StateError::DocumentContestNotPaidForError(e) => { + generic_consensus_error!(DocumentContestNotPaidForError, e).into() + } } } @@ -560,6 +564,13 @@ fn from_basic_error(basic_error: &BasicError) -> JsValue { BasicError::ContestedDocumentsTemporarilyNotAllowedError(e) => { generic_consensus_error!(ContestedDocumentsTemporarilyNotAllowedError, e).into() } + BasicError::WithdrawalOutputScriptNotAllowedWhenSigningWithOwnerKeyError(e) => { + generic_consensus_error!( + WithdrawalOutputScriptNotAllowedWhenSigningWithOwnerKeyError, + e + ) + .into() + } } } diff --git a/packages/wasm-dpp/src/identity/identity_public_key/purpose.rs b/packages/wasm-dpp/src/identity/identity_public_key/purpose.rs index 5e598ffa52..33503d6179 100644 --- a/packages/wasm-dpp/src/identity/identity_public_key/purpose.rs +++ b/packages/wasm-dpp/src/identity/identity_public_key/purpose.rs @@ -15,6 +15,8 @@ pub enum PurposeWasm { SYSTEM = 4, /// this key cannot be used for signing documents VOTING = 5, + /// this key is only for masternode owners + OWNER = 6, } impl From for PurposeWasm { @@ -26,6 +28,7 @@ impl From for PurposeWasm { Purpose::TRANSFER => PurposeWasm::TRANSFER, Purpose::SYSTEM => PurposeWasm::SYSTEM, Purpose::VOTING => PurposeWasm::VOTING, + Purpose::OWNER => PurposeWasm::OWNER, } } } diff --git a/packages/withdrawals-contract/Cargo.toml b/packages/withdrawals-contract/Cargo.toml index f0f0c0c478..3f776fd03c 100644 --- a/packages/withdrawals-contract/Cargo.toml +++ b/packages/withdrawals-contract/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "withdrawals-contract" description = "Witdrawals data contract schema and tools" -version = "1.4.0-dev.3" +version = "1.4.1" edition = "2021" rust-version.workspace = true license = "MIT" diff --git a/packages/withdrawals-contract/package.json b/packages/withdrawals-contract/package.json index 9bc7d9ec6d..89cfc8ebd1 100644 --- a/packages/withdrawals-contract/package.json +++ b/packages/withdrawals-contract/package.json @@ -1,6 +1,6 @@ { "name": "@dashevo/withdrawals-contract", - "version": "1.4.0-dev.3", + "version": "1.4.1", "description": "Data Contract to manipulate and track withdrawals", "scripts": { "build": "", diff --git a/yarn.lock b/yarn.lock index f5f5c44e2c..08923aac7f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1436,7 +1436,7 @@ __metadata: version: 0.0.0-use.local resolution: "@dashevo/bench-suite@workspace:packages/bench-suite" dependencies: - "@dashevo/dashcore-lib": "npm:~0.21.3" + "@dashevo/dashcore-lib": "npm:~0.22.0" "@dashevo/dpns-contract": "workspace:*" "@dashevo/wallet-lib": "workspace:*" "@dashevo/wasm-dpp": "workspace:*" @@ -1469,7 +1469,7 @@ __metadata: "@babel/core": "npm:^7.23.3" "@dashevo/dapi-grpc": "workspace:*" "@dashevo/dash-spv": "workspace:*" - "@dashevo/dashcore-lib": "npm:~0.21.3" + "@dashevo/dashcore-lib": "npm:~0.22.0" "@dashevo/grpc-common": "workspace:*" "@dashevo/wasm-dpp": "workspace:*" assert-browserify: "npm:^2.0.0" @@ -1551,7 +1551,7 @@ __metadata: "@dashevo/bls": "npm:~1.2.9" "@dashevo/dapi-client": "workspace:*" "@dashevo/dapi-grpc": "workspace:*" - "@dashevo/dashcore-lib": "npm:~0.21.3" + "@dashevo/dashcore-lib": "npm:~0.22.0" "@dashevo/dashd-rpc": "npm:^19.0.0" "@dashevo/dp-services-ctl": "github:dashevo/js-dp-services-ctl#v0.19-dev" "@dashevo/grpc-common": "workspace:*" @@ -1600,7 +1600,7 @@ __metadata: dependencies: "@dashevo/dark-gravity-wave": "npm:^1.1.1" "@dashevo/dash-util": "npm:^2.0.3" - "@dashevo/dashcore-lib": "npm:~0.21.3" + "@dashevo/dashcore-lib": "npm:~0.22.0" chai: "npm:^4.3.10" eslint: "npm:^8.53.0" eslint-config-airbnb-base: "npm:^15.0.0" @@ -1624,9 +1624,9 @@ __metadata: languageName: node linkType: hard -"@dashevo/dashcore-lib@npm:~0.21.3": - version: 0.21.3 - resolution: "@dashevo/dashcore-lib@npm:0.21.3" +"@dashevo/dashcore-lib@npm:~0.22.0": + version: 0.22.0 + resolution: "@dashevo/dashcore-lib@npm:0.22.0" dependencies: "@dashevo/bls": "npm:~1.2.9" "@dashevo/x11-hash-js": "npm:^1.0.2" @@ -1640,7 +1640,7 @@ __metadata: ripemd160: "npm:^2.0.2" tsd: "npm:^0.28.1" unorm: "npm:^1.6.0" - checksum: 28e2731ac66c34a7b5e160d270b810456dce3a3e1b5227649845aca510f38f441574d154ed8f0a79b26724124f311a87c8f57d53bfb5fd816223e571484fcc2a + checksum: ac9e268f6ec75f32b2c791f5494ec4a99d67c17ad8f8089d5673b1fd9925ac3f47f4981349f82c30e327aa77ee3c2b935dcad154d215f98c72636800030a0994 languageName: node linkType: hard @@ -1780,7 +1780,7 @@ __metadata: resolution: "@dashevo/platform-test-suite@workspace:packages/platform-test-suite" dependencies: "@dashevo/dapi-client": "workspace:*" - "@dashevo/dashcore-lib": "npm:~0.21.3" + "@dashevo/dashcore-lib": "npm:~0.22.0" "@dashevo/dpns-contract": "workspace:*" "@dashevo/feature-flags-contract": "workspace:*" "@dashevo/grpc-common": "workspace:*" @@ -1884,7 +1884,7 @@ __metadata: dependencies: "@dashevo/dapi-client": "workspace:*" "@dashevo/dash-spv": "workspace:*" - "@dashevo/dashcore-lib": "npm:~0.21.3" + "@dashevo/dashcore-lib": "npm:~0.22.0" "@dashevo/grpc-common": "workspace:*" "@dashevo/wasm-dpp": "workspace:*" "@yarnpkg/pnpify": "npm:^4.0.0-rc.42" @@ -1944,7 +1944,7 @@ __metadata: "@babel/core": "npm:^7.23.3" "@babel/preset-env": "npm:^7.23.3" "@dashevo/bls": "npm:~1.2.9" - "@dashevo/dashcore-lib": "npm:~0.21.3" + "@dashevo/dashcore-lib": "npm:~0.22.0" "@dashevo/dpns-contract": "workspace:*" "@types/bs58": "npm:^4.0.1" "@types/node": "npm:^14.6.0" @@ -6161,10 +6161,10 @@ __metadata: languageName: node linkType: hard -"cookie@npm:~0.4.1": - version: 0.4.1 - resolution: "cookie@npm:0.4.1" - checksum: 0f2defd60ac93645ee31e82d11da695080435eb4fe5bed9b14d2fc4e0621a66f4c5c60f3eb05761df08a9d6279366e8646edfd1654f359d0b5afc25304fc4ddc +"cookie@npm:^0.7.0": + version: 0.7.1 + resolution: "cookie@npm:0.7.1" + checksum: aec6a6aa0781761bf55d60447d6be08861d381136a0fe94aa084fddd4f0300faa2b064df490c6798adfa1ebaef9e0af9b08a189c823e0811b8b313b3d9a03380 languageName: node linkType: hard @@ -6344,7 +6344,7 @@ __metadata: "@dashevo/bls": "npm:~1.2.9" "@dashevo/dapi-client": "workspace:*" "@dashevo/dapi-grpc": "workspace:*" - "@dashevo/dashcore-lib": "npm:~0.21.3" + "@dashevo/dashcore-lib": "npm:~0.22.0" "@dashevo/dashpay-contract": "workspace:*" "@dashevo/dpns-contract": "workspace:*" "@dashevo/grpc-common": "workspace:*" @@ -6421,7 +6421,7 @@ __metadata: "@babel/eslint-parser": "npm:^7.23.3" "@dashevo/bls": "npm:~1.2.9" "@dashevo/dapi-client": "workspace:*" - "@dashevo/dashcore-lib": "npm:~0.21.3" + "@dashevo/dashcore-lib": "npm:~0.22.0" "@dashevo/dashd-rpc": "npm:^19.0.0" "@dashevo/docker-compose": "npm:^0.24.4" "@dashevo/wallet-lib": "workspace:*"