From 70579d128cda94081f1335e3cd3499ff94a7899a Mon Sep 17 00:00:00 2001 From: liamaharon Date: Thu, 14 Nov 2024 20:16:49 +0400 Subject: [PATCH 01/30] op-rbuilder (#244) --- .github/workflows/checks.yaml | 4 +- Cargo.lock | 587 +++++++++++---- Cargo.toml | 61 +- Makefile | 5 +- config-optimism-local.toml | 41 ++ crates/op-rbuilder/Cargo.toml | 58 ++ crates/op-rbuilder/node/Cargo.toml | 40 + crates/op-rbuilder/node/src/args.rs | 155 ++++ crates/op-rbuilder/node/src/lib.rs | 16 + crates/op-rbuilder/node/src/node.rs | 286 ++++++++ crates/op-rbuilder/payload_builder/Cargo.toml | 44 ++ .../payload_builder/src/builder.rs | 690 ++++++++++++++++++ crates/op-rbuilder/payload_builder/src/lib.rs | 8 + crates/op-rbuilder/src/eth_bundle_api.rs | 80 ++ crates/op-rbuilder/src/main.rs | 84 +++ crates/rbuilder/Cargo.toml | 29 +- .../src/backtest/fetch/flashbots_db.rs | 9 +- crates/rbuilder/src/backtest/fetch/mempool.rs | 3 +- crates/rbuilder/src/backtest/mod.rs | 5 +- .../backtest/redistribute/cli/csv_output.rs | 5 +- .../find_landed_orders.rs | 12 +- crates/rbuilder/src/backtest/store.rs | 16 +- .../rbuilder/src/bin/backtest-distribute.rs | 3 +- .../src/building/builders/ordering_builder.rs | 2 +- .../block_building_result_assembler.rs | 3 +- .../parallel_builder/conflict_resolvers.rs | 15 +- .../conflict_resolving_pool.rs | 15 +- .../conflict_task_generator.rs | 13 +- .../building/builders/parallel_builder/mod.rs | 8 +- .../parallel_builder/results_aggregator.rs | 14 +- .../parallel_builder/simulation_cache.rs | 6 +- .../src/building/built_block_trace.rs | 3 +- crates/rbuilder/src/building/order_commit.rs | 10 + .../live_builder/block_output/relay_submit.rs | 3 +- crates/rbuilder/src/live_builder/config.rs | 2 +- crates/rbuilder/src/live_builder/mod.rs | 65 +- .../live_builder/order_input/rpc_server.rs | 5 +- .../payload_events/payload_source.rs | 3 +- .../payload_events/relay_epoch_cache.rs | 2 +- crates/rbuilder/src/mev_boost/error.rs | 12 +- crates/rbuilder/src/mev_boost/mod.rs | 4 +- crates/rbuilder/src/primitives/serialize.rs | 10 +- crates/rbuilder/src/roothash/prefetcher.rs | 5 +- crates/rbuilder/src/utils/mod.rs | 6 +- crates/rbuilder/src/validation_api_client.rs | 4 +- crates/transaction-pool-bundle-ext/Cargo.toml | 14 + .../bundle_pool_ops/rbuilder/Cargo.toml | 27 + .../bundle_pool_ops/rbuilder/src/lib.rs | 280 +++++++ .../src/bundle_supported_pool.rs | 410 +++++++++++ crates/transaction-pool-bundle-ext/src/lib.rs | 28 + .../transaction-pool-bundle-ext/src/traits.rs | 51 ++ docs/LOGS_PRIVACY.md | 14 +- zepter.yaml | 39 + 53 files changed, 3043 insertions(+), 271 deletions(-) create mode 100644 config-optimism-local.toml create mode 100644 crates/op-rbuilder/Cargo.toml create mode 100644 crates/op-rbuilder/node/Cargo.toml create mode 100644 crates/op-rbuilder/node/src/args.rs create mode 100644 crates/op-rbuilder/node/src/lib.rs create mode 100644 crates/op-rbuilder/node/src/node.rs create mode 100644 crates/op-rbuilder/payload_builder/Cargo.toml create mode 100644 crates/op-rbuilder/payload_builder/src/builder.rs create mode 100644 crates/op-rbuilder/payload_builder/src/lib.rs create mode 100644 crates/op-rbuilder/src/eth_bundle_api.rs create mode 100644 crates/op-rbuilder/src/main.rs create mode 100644 crates/transaction-pool-bundle-ext/Cargo.toml create mode 100644 crates/transaction-pool-bundle-ext/bundle_pool_ops/rbuilder/Cargo.toml create mode 100644 crates/transaction-pool-bundle-ext/bundle_pool_ops/rbuilder/src/lib.rs create mode 100644 crates/transaction-pool-bundle-ext/src/bundle_supported_pool.rs create mode 100644 crates/transaction-pool-bundle-ext/src/lib.rs create mode 100644 crates/transaction-pool-bundle-ext/src/traits.rs create mode 100644 zepter.yaml diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index ea919493..15443eec 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -23,7 +23,7 @@ jobs: - stable features: - "" - - "redact_sensitive" + - "redact-sensitive" steps: - name: Checkout sources uses: actions/checkout@v4 @@ -73,7 +73,7 @@ jobs: - stable features: - "" - - "redact_sensitive" + - "redact-sensitive" steps: - name: Checkout sources uses: actions/checkout@v4 diff --git a/Cargo.lock b/Cargo.lock index f4ceab95..05f52404 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -351,7 +351,7 @@ dependencies = [ "futures-utils-wasm", "lru", "pin-project", - "reqwest 0.12.5", + "reqwest 0.12.8", "serde", "serde_json", "thiserror", @@ -416,7 +416,7 @@ dependencies = [ "alloy-transport-ws", "futures", "pin-project", - "reqwest 0.12.5", + "reqwest 0.12.8", "serde", "serde_json", "tokio", @@ -492,7 +492,7 @@ dependencies = [ "derive_more 1.0.0", "ethereum_ssz", "ethereum_ssz_derive", - "jsonrpsee-types 0.24.3", + "jsonrpsee-types 0.24.4", "jsonwebtoken", "rand 0.8.5", "serde", @@ -512,7 +512,7 @@ dependencies = [ "alloy-serde", "alloy-sol-types", "itertools 0.13.0", - "jsonrpsee-types 0.24.3", + "jsonrpsee-types 0.24.4", "serde", "serde_json", "thiserror", @@ -696,7 +696,7 @@ checksum = "bc10c4dd932f66e0db6cc5735241e0c17a6a18564b430bbc1839f7db18587a93" dependencies = [ "alloy-json-rpc", "alloy-transport", - "reqwest 0.12.5", + "reqwest 0.12.8", "serde_json", "tower", "tracing", @@ -798,9 +798,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" [[package]] name = "anstyle-parse" @@ -1133,9 +1133,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.81" +version = "0.1.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", @@ -1280,7 +1280,7 @@ name = "beacon-api-client" version = "0.1.0" source = "git+https://github.com/ralexstokes/ethereum-consensus/?rev=cf3c404043230559660810bc0c9d6d5a8498d819#cf3c404043230559660810bc0c9d6d5a8498d819" dependencies = [ - "clap 4.5.10", + "clap 4.5.19", "ethereum-consensus", "http 0.2.12", "itertools 0.10.5", @@ -1351,7 +1351,7 @@ dependencies = [ "bitflags 2.6.0", "cexpr", "clang-sys", - "itertools 0.12.1", + "itertools 0.11.0", "lazy_static", "lazycell", "proc-macro2", @@ -1791,9 +1791,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.10" +version = "4.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f6b81fb3c84f5563d509c59b5a48d935f689e993afa90fe39047f05adef9142" +checksum = "7be5744db7978a28d9df86a214130d106a89ce49644cbc4e3f0c22c3fba30615" dependencies = [ "clap_builder", "clap_derive", @@ -1801,9 +1801,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.10" +version = "4.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca6706fd5224857d9ac5eb9355f6683563cc0541c7cd9d014043b57cbec78ac" +checksum = "a5fbc17d3ef8278f55b282b2a2e75ae6f6c7d4bb70ed3d0382375104bfafdb4b" dependencies = [ "anstream", "anstyle", @@ -1813,9 +1813,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.8" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bac35c6dafb060fd4d275d9a4ffae97917c13a6327903a8be2153cd964f7085" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -2064,7 +2064,7 @@ dependencies = [ "anes", "cast", "ciborium", - "clap 4.5.10", + "clap 4.5.19", "criterion-plot", "futures", "is-terminal", @@ -4274,7 +4274,7 @@ dependencies = [ "socket2 0.5.7", "widestring", "windows-sys 0.48.0", - "winreg 0.50.0", + "winreg", ] [[package]] @@ -4328,15 +4328,6 @@ dependencies = [ "either", ] -[[package]] -name = "itertools" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.13.0" @@ -4410,18 +4401,18 @@ dependencies = [ [[package]] name = "jsonrpsee" -version = "0.24.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ec465b607a36dc5dd45d48b7689bc83f679f66a3ac6b6b21cc787a11e0f8685" -dependencies = [ - "jsonrpsee-client-transport 0.24.3", - "jsonrpsee-core 0.24.3", - "jsonrpsee-http-client 0.24.3", - "jsonrpsee-proc-macros 0.24.3", - "jsonrpsee-server 0.24.3", - "jsonrpsee-types 0.24.3", - "jsonrpsee-wasm-client 0.24.3", - "jsonrpsee-ws-client 0.24.3", +version = "0.24.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd1ead9fb95614e8dc5556d12a8681c2f6d352d0c1d3efc8708c7ccbba47bc6" +dependencies = [ + "jsonrpsee-client-transport 0.24.4", + "jsonrpsee-core 0.24.4", + "jsonrpsee-http-client 0.24.4", + "jsonrpsee-proc-macros 0.24.4", + "jsonrpsee-server 0.24.4", + "jsonrpsee-types 0.24.4", + "jsonrpsee-wasm-client 0.24.4", + "jsonrpsee-ws-client 0.24.4", "tokio", "tracing", ] @@ -4451,16 +4442,16 @@ dependencies = [ [[package]] name = "jsonrpsee-client-transport" -version = "0.24.3" +version = "0.24.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f0977f9c15694371b8024c35ab58ca043dbbf4b51ccb03db8858a021241df1" +checksum = "89841d4f03a14c055eb41d4f41901819573ef948e8ee0d5c86466fd286b2ce7f" dependencies = [ "base64 0.22.1", "futures-channel", "futures-util", "gloo-net 0.6.0", "http 1.1.0", - "jsonrpsee-core 0.24.3", + "jsonrpsee-core 0.24.4", "pin-project", "rustls 0.23.12", "rustls-pki-types", @@ -4502,9 +4493,9 @@ dependencies = [ [[package]] name = "jsonrpsee-core" -version = "0.24.3" +version = "0.24.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e942c55635fbf5dc421938b8558a8141c7e773720640f4f1dbe1f4164ca4e221" +checksum = "ff79651479f69ada7bda604ef2acf3f1aa50755d97cc36d25ff04c2664f9d96f" dependencies = [ "async-trait", "bytes", @@ -4513,7 +4504,7 @@ dependencies = [ "http 1.1.0", "http-body 1.0.1", "http-body-util", - "jsonrpsee-types 0.24.3", + "jsonrpsee-types 0.24.4", "parking_lot 0.12.3", "pin-project", "rand 0.8.5", @@ -4549,9 +4540,9 @@ dependencies = [ [[package]] name = "jsonrpsee-http-client" -version = "0.24.3" +version = "0.24.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33774602df12b68a2310b38a535733c477ca4a498751739f89fe8dbbb62ec4c" +checksum = "68ed8b301b19f4dad8ddc66ed956a70fc227def5c19b3898e0a29ce8f0edee06" dependencies = [ "async-trait", "base64 0.22.1", @@ -4559,8 +4550,8 @@ dependencies = [ "hyper 1.4.1", "hyper-rustls 0.27.2", "hyper-util", - "jsonrpsee-core 0.24.3", - "jsonrpsee-types 0.24.3", + "jsonrpsee-core 0.24.4", + "jsonrpsee-types 0.24.4", "rustls 0.23.12", "rustls-platform-verifier", "serde", @@ -4587,9 +4578,9 @@ dependencies = [ [[package]] name = "jsonrpsee-proc-macros" -version = "0.24.3" +version = "0.24.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b07a2daf52077ab1b197aea69a5c990c060143835bf04c77070e98903791715" +checksum = "a0d4c6bec4909c966f59f52db3655c0e9d4685faae8b49185973d9d7389bb884" dependencies = [ "heck 0.5.0", "proc-macro-crate 3.1.0", @@ -4623,9 +4614,9 @@ dependencies = [ [[package]] name = "jsonrpsee-server" -version = "0.24.3" +version = "0.24.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038fb697a709bec7134e9ccbdbecfea0e2d15183f7140254afef7c5610a3f488" +checksum = "ebe2198e5fd96cf2153ecc123364f699b6e2151317ea09c7bf799c43c2fe1415" dependencies = [ "futures-util", "http 1.1.0", @@ -4633,8 +4624,8 @@ dependencies = [ "http-body-util", "hyper 1.4.1", "hyper-util", - "jsonrpsee-core 0.24.3", - "jsonrpsee-types 0.24.3", + "jsonrpsee-core 0.24.4", + "jsonrpsee-types 0.24.4", "pin-project", "route-recognizer", "serde", @@ -4664,9 +4655,9 @@ dependencies = [ [[package]] name = "jsonrpsee-types" -version = "0.24.3" +version = "0.24.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b67d6e008164f027afbc2e7bb79662650158d26df200040282d2aa1cbb093b" +checksum = "531e386460425e49679587871a056f2895a47dade21457324ad1262cd78ef6d9" dependencies = [ "http 1.1.0", "serde", @@ -4687,13 +4678,13 @@ dependencies = [ [[package]] name = "jsonrpsee-wasm-client" -version = "0.24.3" +version = "0.24.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0470d0ae043ffcb0cd323797a631e637fb4b55fe3eaa6002934819458bba62a7" +checksum = "5a2d2206c8f04c6b79a11bd1d92d6726b6f7fd3dec57c91e07fa53e867268bbb" dependencies = [ - "jsonrpsee-client-transport 0.24.3", - "jsonrpsee-core 0.24.3", - "jsonrpsee-types 0.24.3", + "jsonrpsee-client-transport 0.24.4", + "jsonrpsee-core 0.24.4", + "jsonrpsee-types 0.24.4", ] [[package]] @@ -4711,14 +4702,14 @@ dependencies = [ [[package]] name = "jsonrpsee-ws-client" -version = "0.24.3" +version = "0.24.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "992bf67d1132f88edf4a4f8cff474cf01abb2be203004a2b8e11c2b20795b99e" +checksum = "87bc869e143d430e748988261d19b630e8f1692074e68f1a7f0eb4c521d2fc58" dependencies = [ "http 1.1.0", - "jsonrpsee-client-transport 0.24.3", - "jsonrpsee-core 0.24.3", - "jsonrpsee-types 0.24.3", + "jsonrpsee-client-transport 0.24.4", + "jsonrpsee-core 0.24.4", + "jsonrpsee-types 0.24.4", "url", ] @@ -4774,9 +4765,9 @@ dependencies = [ [[package]] name = "keccak-asm" -version = "0.1.4" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "505d1856a39b200489082f90d897c3f07c455563880bc5952e38eabf731c83b6" +checksum = "47a3633291834c4fbebf8673acbc1b04ec9d151418ff9b8e26dcd79129928758" dependencies = [ "digest 0.10.7", "sha3-asm", @@ -5199,7 +5190,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b453bd8e35ec92138b093172731fe7920cdf397f2a709e789243147a79772b9d" dependencies = [ "chrono", - "clap 4.5.10", + "clap 4.5.19", "csv", "eyre", "indicatif", @@ -5820,9 +5811,9 @@ dependencies = [ [[package]] name = "op-alloy-network" -version = "0.2.7" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf926fccb35a1ad784cf8c2771a3a7b2c891379fcc78bc7cdc23dec1b57a6459" +checksum = "66184e6c92269ba4ef1f80e8566ce11d41b584884ce7476d4b1b5e0e38503ecb" dependencies = [ "alloy-consensus", "alloy-eips", @@ -5835,9 +5826,9 @@ dependencies = [ [[package]] name = "op-alloy-rpc-types" -version = "0.2.7" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f57a192b16bd94296637616908a5701d4318d6c2c5119c93a1df5442ec97c13" +checksum = "e9c604cd3b9680d0edd0b7127f3550bcff634c2d2efe27b2b4853e72320186a8" dependencies = [ "alloy-network", "alloy-primitives 0.8.0", @@ -5860,6 +5851,72 @@ dependencies = [ "serde", ] +[[package]] +name = "op-rbuilder" +version = "0.1.0" +dependencies = [ + "async-trait", + "clap_builder", + "jsonrpsee 0.24.4", + "op-rbuilder-node-optimism", + "rbuilder", + "reth", + "reth-cli-util", + "reth-discv4", + "reth-node-optimism", + "reth-optimism-rpc", + "tikv-jemallocator", + "tokio", + "tracing", + "transaction-pool-bundle-ext", +] + +[[package]] +name = "op-rbuilder-node-optimism" +version = "0.0.0" +dependencies = [ + "clap 4.5.19", + "eyre", + "op-rbuilder-payload-builder", + "rbuilder-bundle-pool-operations", + "reth-basic-payload-builder", + "reth-chainspec", + "reth-evm", + "reth-evm-optimism", + "reth-node-builder", + "reth-node-optimism", + "reth-payload-builder", + "reth-primitives", + "reth-provider", + "reth-tracing", + "reth-transaction-pool", + "tracing", + "transaction-pool-bundle-ext", +] + +[[package]] +name = "op-rbuilder-payload-builder" +version = "0.1.0" +dependencies = [ + "reth-basic-payload-builder", + "reth-chain-state", + "reth-chainspec", + "reth-evm", + "reth-evm-optimism", + "reth-execution-types", + "reth-node-optimism", + "reth-optimism-payload-builder", + "reth-payload-builder", + "reth-primitives", + "reth-provider", + "reth-revm", + "reth-rpc-types", + "reth-trie", + "revm", + "tracing", + "transaction-pool-bundle-ext", +] + [[package]] name = "opaque-debug" version = "0.3.1" @@ -5962,6 +6019,18 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa 0.16.9", + "elliptic-curve 0.13.8", + "primeorder", + "sha2 0.10.8", +] + [[package]] name = "page_size" version = "0.6.0" @@ -6675,6 +6744,15 @@ dependencies = [ "termtree", ] +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve 0.13.8", +] + [[package]] name = "primitive-types" version = "0.12.2" @@ -7109,7 +7187,7 @@ dependencies = [ "beacon-api-client", "bigdecimal 0.4.5", "built", - "clap 4.5.10", + "clap 4.5.19", "criterion 0.5.1", "crossbeam", "crossbeam-queue", @@ -7147,7 +7225,7 @@ dependencies = [ "rand 0.8.5", "rayon", "redis", - "reqwest 0.11.27", + "reqwest 0.12.8", "reth", "reth-basic-payload-builder", "reth-chainspec", @@ -7193,6 +7271,23 @@ dependencies = [ "zip", ] +[[package]] +name = "rbuilder-bundle-pool-operations" +version = "0.1.0" +dependencies = [ + "derive_more 1.0.0", + "eyre", + "rbuilder", + "reth-db-api", + "reth-primitives", + "reth-provider", + "reth-rpc-types", + "tokio", + "tokio-util", + "tracing", + "transaction-pool-bundle-ext", +] + [[package]] name = "recvmsg" version = "1.0.0" @@ -7325,7 +7420,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "sync_wrapper 0.1.2", - "system-configuration", + "system-configuration 0.5.1", "tokio", "tokio-native-tls", "tokio-util", @@ -7335,19 +7430,22 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams", "web-sys", - "winreg 0.50.0", + "winreg", ] [[package]] name = "reqwest" -version = "0.12.5" +version = "0.12.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37" +checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b" dependencies = [ "base64 0.22.1", "bytes", + "encoding_rs", + "futures-channel", "futures-core", "futures-util", + "h2 0.4.5", "http 1.1.0", "http-body 1.0.1", "http-body-util", @@ -7365,13 +7463,14 @@ dependencies = [ "pin-project-lite", "quinn", "rustls 0.23.12", - "rustls-native-certs 0.7.1", + "rustls-native-certs 0.8.0", "rustls-pemfile 2.1.2", "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", "sync_wrapper 1.0.1", + "system-configuration 0.6.1", "tokio", "tokio-native-tls", "tokio-rustls 0.26.0", @@ -7381,7 +7480,7 @@ dependencies = [ "wasm-bindgen-futures", "web-sys", "webpki-roots 0.26.3", - "winreg 0.52.0", + "windows-registry", ] [[package]] @@ -7402,7 +7501,7 @@ dependencies = [ "alloy-rlp", "aquamarine", "backon", - "clap 4.5.10", + "clap 4.5.19", "discv5", "eyre", "fdlimit", @@ -7440,6 +7539,8 @@ dependencies = [ "reth-node-ethereum", "reth-node-events", "reth-node-metrics", + "reth-node-optimism", + "reth-optimism-cli", "reth-optimism-primitives", "reth-optimism-rpc", "reth-payload-builder", @@ -7642,13 +7743,25 @@ dependencies = [ "auto_impl", "derive_more 1.0.0", "once_cell", + "op-alloy-rpc-types", "reth-ethereum-forks", "reth-network-peers", "reth-primitives-traits", "reth-trie-common", + "serde", "serde_json", ] +[[package]] +name = "reth-cli" +version = "1.0.6" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +dependencies = [ + "clap 4.5.19", + "eyre", + "reth-cli-runner", +] + [[package]] name = "reth-cli-commands" version = "1.0.6" @@ -7656,7 +7769,7 @@ source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18 dependencies = [ "ahash", "backon", - "clap 4.5.10", + "clap 4.5.19", "comfy-table", "crossterm", "eyre", @@ -7800,7 +7913,7 @@ dependencies = [ "auto_impl", "eyre", "futures", - "reqwest 0.12.5", + "reqwest 0.12.8", "reth-node-api", "reth-node-core", "reth-rpc-api", @@ -8344,6 +8457,7 @@ name = "reth-execution-types" version = "1.0.6" source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" dependencies = [ + "reth-chainspec", "reth-execution-errors", "reth-primitives", "reth-trie", @@ -8406,7 +8520,7 @@ dependencies = [ "futures", "futures-util", "interprocess", - "jsonrpsee 0.24.3", + "jsonrpsee 0.24.4", "pin-project", "serde_json", "thiserror", @@ -8479,7 +8593,7 @@ version = "1.0.6" source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" dependencies = [ "futures-util", - "reqwest 0.12.5", + "reqwest 0.12.8", "serde_with", "thiserror", "tokio", @@ -8705,7 +8819,7 @@ source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18 dependencies = [ "alloy-genesis", "alloy-rpc-types-engine", - "clap 4.5.10", + "clap 4.5.19", "const_format", "derive_more 1.0.0", "dirs-next", @@ -8726,6 +8840,7 @@ dependencies = [ "reth-network", "reth-network-p2p", "reth-network-peers", + "reth-optimism-chainspec", "reth-primitives", "reth-provider", "reth-prune-types", @@ -8801,7 +8916,7 @@ source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18 dependencies = [ "eyre", "http 1.1.0", - "jsonrpsee 0.24.3", + "jsonrpsee 0.24.4", "metrics", "metrics-exporter-prometheus", "metrics-process", @@ -8818,6 +8933,103 @@ dependencies = [ "vergen", ] +[[package]] +name = "reth-node-optimism" +version = "1.0.6" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +dependencies = [ + "async-trait", + "clap 4.5.19", + "eyre", + "jsonrpsee 0.24.4", + "jsonrpsee-types 0.24.4", + "parking_lot 0.12.3", + "reqwest 0.12.8", + "reth-auto-seal-consensus", + "reth-basic-payload-builder", + "reth-beacon-consensus", + "reth-chainspec", + "reth-consensus", + "reth-discv5", + "reth-evm", + "reth-evm-optimism", + "reth-network", + "reth-node-api", + "reth-node-builder", + "reth-optimism-chainspec", + "reth-optimism-consensus", + "reth-optimism-payload-builder", + "reth-optimism-rpc", + "reth-payload-builder", + "reth-primitives", + "reth-provider", + "reth-revm", + "reth-rpc", + "reth-rpc-eth-api", + "reth-rpc-eth-types", + "reth-rpc-types", + "reth-rpc-types-compat", + "reth-tracing", + "reth-transaction-pool", + "serde", + "serde_json", + "thiserror", + "tracing", +] + +[[package]] +name = "reth-optimism-chainspec" +version = "1.0.6" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +dependencies = [ + "alloy-chains", + "alloy-primitives 0.8.0", + "derive_more 1.0.0", + "once_cell", + "reth-chainspec", + "reth-ethereum-forks", + "reth-primitives-traits", + "serde_json", +] + +[[package]] +name = "reth-optimism-cli" +version = "1.0.6" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +dependencies = [ + "alloy-primitives 0.8.0", + "alloy-rlp", + "clap 4.5.19", + "eyre", + "futures-util", + "reth-chainspec", + "reth-cli", + "reth-cli-commands", + "reth-config", + "reth-consensus", + "reth-db", + "reth-db-api", + "reth-downloaders", + "reth-errors", + "reth-evm-optimism", + "reth-execution-types", + "reth-network-p2p", + "reth-node-core", + "reth-node-events", + "reth-optimism-chainspec", + "reth-optimism-primitives", + "reth-primitives", + "reth-provider", + "reth-prune", + "reth-stages", + "reth-stages-types", + "reth-static-file", + "reth-static-file-types", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "reth-optimism-consensus" version = "1.0.6" @@ -8830,6 +9042,33 @@ dependencies = [ "tracing", ] +[[package]] +name = "reth-optimism-payload-builder" +version = "1.0.6" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +dependencies = [ + "alloy-rlp", + "reth-basic-payload-builder", + "reth-chain-state", + "reth-chainspec", + "reth-evm", + "reth-evm-optimism", + "reth-execution-types", + "reth-payload-builder", + "reth-payload-primitives", + "reth-primitives", + "reth-provider", + "reth-revm", + "reth-rpc-types", + "reth-rpc-types-compat", + "reth-transaction-pool", + "reth-trie", + "revm", + "sha2 0.10.8", + "thiserror", + "tracing", +] + [[package]] name = "reth-optimism-primitives" version = "1.0.6" @@ -8841,10 +9080,10 @@ version = "1.0.6" source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" dependencies = [ "alloy-primitives 0.8.0", - "jsonrpsee-types 0.24.3", + "jsonrpsee-types 0.24.4", "op-alloy-network", "parking_lot 0.12.3", - "reqwest 0.12.5", + "reqwest 0.12.8", "reth-chainspec", "reth-evm", "reth-evm-optimism", @@ -8941,6 +9180,7 @@ dependencies = [ "reth-chainspec", "reth-codecs", "reth-ethereum-forks", + "reth-optimism-chainspec", "reth-primitives-traits", "reth-static-file-types", "reth-trie-common", @@ -9059,7 +9299,7 @@ dependencies = [ name = "reth-rbuilder" version = "0.1.0" dependencies = [ - "clap 4.5.10", + "clap 4.5.19", "eyre", "libc", "rbuilder", @@ -9105,7 +9345,7 @@ dependencies = [ "http 1.1.0", "http-body 1.0.1", "hyper 1.4.1", - "jsonrpsee 0.24.3", + "jsonrpsee 0.24.4", "jsonwebtoken", "parking_lot 0.12.3", "pin-project", @@ -9151,7 +9391,7 @@ version = "1.0.6" source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" dependencies = [ "alloy-json-rpc", - "jsonrpsee 0.24.3", + "jsonrpsee 0.24.4", "reth-engine-primitives", "reth-network-peers", "reth-primitives", @@ -9165,7 +9405,7 @@ version = "1.0.6" source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" dependencies = [ "http 1.1.0", - "jsonrpsee 0.24.3", + "jsonrpsee 0.24.4", "metrics", "pin-project", "reth-chainspec", @@ -9198,8 +9438,8 @@ version = "1.0.6" source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" dependencies = [ "async-trait", - "jsonrpsee-core 0.24.3", - "jsonrpsee-types 0.24.3", + "jsonrpsee-core 0.24.4", + "jsonrpsee-types 0.24.4", "metrics", "reth-beacon-consensus", "reth-chainspec", @@ -9232,8 +9472,8 @@ dependencies = [ "auto_impl", "dyn-clone", "futures", - "jsonrpsee 0.24.3", - "jsonrpsee-types 0.24.3", + "jsonrpsee 0.24.4", + "jsonrpsee-types 0.24.4", "parking_lot 0.12.3", "reth-chainspec", "reth-errors", @@ -9265,8 +9505,8 @@ dependencies = [ "alloy-sol-types", "derive_more 1.0.0", "futures", - "jsonrpsee-core 0.24.3", - "jsonrpsee-types 0.24.3", + "jsonrpsee-core 0.24.4", + "jsonrpsee-types 0.24.4", "metrics", "rand 0.8.5", "reth-chain-state", @@ -9302,7 +9542,7 @@ source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18 dependencies = [ "alloy-rpc-types-engine", "http 1.1.0", - "jsonrpsee-http-client 0.24.3", + "jsonrpsee-http-client 0.24.4", "pin-project", "tower", "tracing", @@ -9314,8 +9554,8 @@ version = "1.0.6" source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" dependencies = [ "alloy-primitives 0.8.0", - "jsonrpsee-core 0.24.3", - "jsonrpsee-types 0.24.3", + "jsonrpsee-core 0.24.4", + "jsonrpsee-types 0.24.4", "reth-errors", "reth-network-api", "reth-primitives", @@ -9339,7 +9579,7 @@ dependencies = [ "alloy-rpc-types-trace", "alloy-rpc-types-txpool", "alloy-serde", - "jsonrpsee-types 0.24.3", + "jsonrpsee-types 0.24.4", "op-alloy-rpc-types", "op-alloy-rpc-types-engine", ] @@ -9456,7 +9696,7 @@ version = "1.0.6" source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" dependencies = [ "alloy-primitives 0.8.0", - "clap 4.5.10", + "clap 4.5.19", "derive_more 1.0.0", "serde", "strum", @@ -9522,7 +9762,7 @@ name = "reth-tracing" version = "1.0.6" source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" dependencies = [ - "clap 4.5.10", + "clap 4.5.19", "eyre", "rolling-file", "tracing", @@ -9710,6 +9950,7 @@ dependencies = [ "cfg-if", "k256 0.13.3", "once_cell", + "p256", "revm-primitives", "ripemd", "secp256k1", @@ -10002,6 +10243,19 @@ dependencies = [ "security-framework", ] +[[package]] +name = "rustls-native-certs" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcaf18a4f2be7326cd874a5fa579fae794320a0f388d365dca7e480e55f83f8a" +dependencies = [ + "openssl-probe", + "rustls-pemfile 2.1.2", + "rustls-pki-types", + "schannel", + "security-framework", +] + [[package]] name = "rustls-pemfile" version = "1.0.4" @@ -10329,9 +10583,9 @@ checksum = "a3f0bf26fd526d2a95683cd0f87bf103b8539e2ca1ef48ce002d67aad59aa0b4" [[package]] name = "serde" -version = "1.0.204" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] @@ -10347,9 +10601,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.204" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", @@ -10358,12 +10612,13 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.120" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ "indexmap 2.2.6", "itoa", + "memchr", "ryu", "serde", ] @@ -10517,9 +10772,9 @@ dependencies = [ [[package]] name = "sha3-asm" -version = "0.1.4" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28efc5e327c837aa837c59eae585fc250715ef939ac32881bcc11677cd02d46" +checksum = "a9b57fd861253bff08bb1919e995f90ba8f4889de2726091c8876f3a4e823b40" dependencies = [ "cc", "cfg-if", @@ -11244,6 +11499,9 @@ name = "sync_wrapper" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +dependencies = [ + "futures-core", +] [[package]] name = "synstructure" @@ -11293,7 +11551,18 @@ checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" dependencies = [ "bitflags 1.3.2", "core-foundation", - "system-configuration-sys", + "system-configuration-sys 0.5.0", +] + +[[package]] +name = "system-configuration" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +dependencies = [ + "bitflags 2.6.0", + "core-foundation", + "system-configuration-sys 0.6.0", ] [[package]] @@ -11306,6 +11575,16 @@ dependencies = [ "libc", ] +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "tap" version = "1.0.1" @@ -11366,18 +11645,18 @@ checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" [[package]] name = "thiserror" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ "proc-macro2", "quote", @@ -11523,9 +11802,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.39.1" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d040ac2b29ab03b09d4129c2f5bbd012a3ac2f79d38ff506a4bf8dd34b0eac8a" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" dependencies = [ "backtrace", "bytes", @@ -11583,9 +11862,9 @@ dependencies = [ [[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", @@ -11623,9 +11902,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" dependencies = [ "bytes", "futures-core", @@ -11874,6 +12153,18 @@ dependencies = [ "tracing-serde", ] +[[package]] +name = "transaction-pool-bundle-ext" +version = "0.1.0" +dependencies = [ + "reth", + "reth-eth-wire-types", + "reth-primitives", + "reth-rpc-types", + "reth-transaction-pool", + "tokio", +] + [[package]] name = "triehash" version = "0.8.4" @@ -12478,7 +12769,7 @@ checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" dependencies = [ "windows-implement", "windows-interface", - "windows-result", + "windows-result 0.1.2", "windows-targets 0.52.6", ] @@ -12504,6 +12795,17 @@ dependencies = [ "syn 2.0.72", ] +[[package]] +name = "windows-registry" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +dependencies = [ + "windows-result 0.2.0", + "windows-strings", + "windows-targets 0.52.6", +] + [[package]] name = "windows-result" version = "0.1.2" @@ -12513,6 +12815,25 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result 0.2.0", + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -12680,16 +13001,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "winreg" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - [[package]] name = "ws_stream_wasm" version = "0.7.4" diff --git a/Cargo.toml b/Cargo.toml index 1515e80b..227e1f68 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,11 +1,17 @@ [workspace] members = [ "crates/rbuilder", + "crates/op-rbuilder", + "crates/op-rbuilder/payload_builder", + "crates/op-rbuilder/node", "crates/reth-rbuilder", "crates/rbuilder/src/test_utils", "crates/rbuilder/src/telemetry/metrics_macros", - "crates/eth-sparse-mpt", + "crates/transaction-pool-bundle-ext", + "crates/transaction-pool-bundle-ext/bundle_pool_ops/rbuilder", + "crates/eth-sparse-mpt" ] +default-members = ["crates/rbuilder"] resolver = "2" # Like release, but with full debug symbols. Useful for e.g. `perf`. @@ -25,6 +31,8 @@ edition = "2021" [workspace.dependencies] reth = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } +reth-chain-state = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } +reth-beacon-consensus = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } reth-cli-util = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } reth-db = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } reth-db-api = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } @@ -32,18 +40,42 @@ reth-db-common = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } reth-errors = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } reth-libmdbx = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } reth-payload-builder = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } +reth-payload-primitives = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } reth-node-api = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } reth-node-builder = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } reth-node-ethereum = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } reth-trie = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } reth-trie-parallel = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } +reth-transaction-pool = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } reth-basic-payload-builder = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } reth-node-core = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } +reth-consensus = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } +reth-optimism-consensus = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } +reth-auto-seal-consensus = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } reth-primitives = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } reth-provider = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6", features = ["test-utils"] } reth-chainspec = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } +reth-execution-types = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } +reth-revm = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } reth-evm = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } reth-evm-ethereum = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } +reth-evm-optimism = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } +reth-rpc = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } +reth-tracing = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } +reth-rpc-types = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } +reth-rpc-types-compat = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } +reth-rpc-eth-api = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } +reth-rpc-eth-types = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } +reth-rpc-api-types = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } +reth-discv4 = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } +reth-discv5 = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } +reth-network = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } +reth-node-optimism = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } +reth-eth-wire-types = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } +reth-storage-api = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } +reth-optimism-rpc = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } +reth-optimism-payload-builder = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } +reth-optimism-chainspec = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } reth-execution-errors = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } reth-trie-db = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } @@ -66,7 +98,7 @@ alloy-rlp = "0.3.4" alloy-chains = "0.1.23" alloy-provider = { version = "0.3.0", features = ["ipc", "pubsub"] } alloy-pubsub = { version = "0.3.0" } -alloy-eips = { version = "0.3.0" } +alloy-eips = { version = "0.3.6" } alloy-rpc-types = { version = "0.3.0" } alloy-json-rpc = { version = "0.3.0" } alloy-transport-http = { version = "0.3.0" } @@ -75,7 +107,7 @@ alloy-transport = { version = "0.3.0" } alloy-node-bindings = { version = "0.3.0" } alloy-consensus = { version = "0.3.0", features = ["kzg"] } alloy-serde = { version = "0.3.0" } -alloy-rpc-types-beacon = { version = "0.3.0", features = [ +alloy-rpc-types-beacon = { version = "0.3.6", features = [ "ssz", ] } alloy-rpc-types-engine = { version = "0.3.0", features = [ @@ -83,15 +115,30 @@ alloy-rpc-types-engine = { version = "0.3.0", features = [ ] } alloy-rpc-types-eth = { version = "0.3.0" } alloy-signer-local = { version = "0.3.0" } +alloy-genesis = { version = "0.3.0" } alloy-trie = { version = "0.5.0" } +async-trait = { version = "0.1.83" } clap = { version = "4.4.3" } -eyre = { version = "0.6.8" } +thiserror = { version = "1.0.64" } +eyre = { version = "0.6.12" } +tracing = { version = "0.1.37" } +jsonrpsee = { version = "0.24.4" } +jsonrpsee-types = { version = "0.24.4" } +parking_lot = { version = "0.12.3" } +tokio = { version = "1.40.0" } +auto_impl = { version = "1.2.0" } +reqwest = { version = "0.12.8" } +serde = { version = "1.0.210" } +serde_json = { version = "1.0.128" } +clap_builder = { version = "4.5.19" } +derive_more = { version = "1" } +tokio-stream = "0.1.16" +tokio-util = "0.7.12" +url = "2.5.2" + libc = { version = "0.2.161" } tikv-jemallocator = { version = "0.5.4" } -tokio = "1.38.0" -tokio-util = "0.7.11" -tracing = "0.1.37" eth-sparse-mpt = { path = "crates/eth-sparse-mpt" } diff --git a/Makefile b/Makefile index 7078179b..db52f033 100644 --- a/Makefile +++ b/Makefile @@ -37,10 +37,12 @@ docker-image: ## Build a rbuilder Docker image lint: ## Run the linters cargo fmt -- --check cargo clippy --features "$(FEATURES)" -- -D warnings + cargo clippy -p op-rbuilder --features "$(FEATURES),optimism" -- -D warnings .PHONY: test -test: ## Run the tests +test: ## Run the tests for rbuilder and op-rbuilder cargo test --verbose --features "$(FEATURES)" + cargo test -p op-rbuilder --verbose --features "$(FEATURES),optimism" .PHONY: lt lt: lint test ## Run "lint" and "test" @@ -50,6 +52,7 @@ fmt: ## Format the code cargo fmt cargo fix --allow-staged cargo clippy --features "$(FEATURES)" --fix --allow-staged + cargo clippy -p op-rbuilder --features "$(FEATURES),optimism" --fix --allow-staged .PHONY: bench bench: ## Run benchmarks diff --git a/config-optimism-local.toml b/config-optimism-local.toml new file mode 100644 index 00000000..c7ce4b17 --- /dev/null +++ b/config-optimism-local.toml @@ -0,0 +1,41 @@ +log_json = false +log_level = "info,rbuilder=debug" +redacted_telemetry_server_port = 6061 +redacted_telemetry_server_ip = "0.0.0.0" +full_telemetry_server_port = 6060 +full_telemetry_server_ip = "0.0.0.0" + +chain = "$HOME/grimoire/optimism/.devnet/genesis-l2.json" +reth_datadir = "$HOME/.playground/devnet/data_reth" +relay_secret_key = "5eae315483f028b5cdd5d1090ff0c7618b18737ea9bf3c35047189db22835c48" +coinbase_secret_key = "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" + +cl_node_url = ["http://localhost:3500"] +jsonrpc_server_port = 8645 +jsonrpc_server_ip = "0.0.0.0" +el_node_ipc_path = "/tmp/reth.ipc" +extra_data = "⚡🤖" + +dry_run = false +dry_run_validation_url = "http://localhost:8545" + +ignore_cancellable_orders = true + +sbundle_mergeabe_signers = [] +live_builders = ["mp-ordering"] + +[[relays]] +name = "custom" +url = "http://0xac6e77dfe25ecd6110b8e780608cce0dab71fdd5ebea22a16c0205200f2f8e2e3ad3b71d3499c54ad14d6c21b41a37ae@localhost:5555" +priority = 0 +use_ssz_for_submit = false +use_gzip_for_submit = false + +[[builders]] +name = "mgp-ordering" +algo = "ordering-builder" +discard_txs = true +sorting = "mev-gas-price" +failed_order_retries = 1 +drop_failed_orders = true + diff --git a/crates/op-rbuilder/Cargo.toml b/crates/op-rbuilder/Cargo.toml new file mode 100644 index 00000000..c75a6f0f --- /dev/null +++ b/crates/op-rbuilder/Cargo.toml @@ -0,0 +1,58 @@ +[package] +name = "op-rbuilder" +version = "0.1.0" +edition = "2021" + +[dependencies] +rbuilder = { path = "../rbuilder" } +op-rbuilder-node-optimism = { path = "./node" } +transaction-pool-bundle-ext = { path = "../transaction-pool-bundle-ext" } + +reth.workspace = true +reth-node-optimism.workspace = true +reth-cli-util.workspace = true +reth-optimism-rpc.workspace = true + +tokio.workspace = true +tracing.workspace = true +jsonrpsee = { workspace = true } +async-trait = { workspace = true } +clap_builder = { workspace = true } + +[target.'cfg(unix)'.dependencies] +tikv-jemallocator = { version = "0.5.0", optional = true } + +[dev-dependencies] +reth-discv4.workspace = true + +[features] +default = ["jemalloc"] + +jemalloc = ["dep:tikv-jemallocator"] +jemalloc-prof = [ + "jemalloc", + "tikv-jemallocator?/profiling", + "reth/jemalloc-prof" +] + +min-error-logs = ["tracing/release_max_level_error"] +min-warn-logs = ["tracing/release_max_level_warn"] +min-info-logs = ["tracing/release_max_level_info"] +min-debug-logs = ["tracing/release_max_level_debug"] +min-trace-logs = ["tracing/release_max_level_trace"] + +optimism = [ + "reth-node-optimism/optimism", + "reth/optimism", + "reth-optimism-rpc/optimism", + "op-rbuilder-node-optimism/optimism", + "rbuilder/optimism" +] + +redact-sensitive = [ + "rbuilder/redact-sensitive" +] + +[[bin]] +name = "op-rbuilder" +path = "src/main.rs" diff --git a/crates/op-rbuilder/node/Cargo.toml b/crates/op-rbuilder/node/Cargo.toml new file mode 100644 index 00000000..350dc79d --- /dev/null +++ b/crates/op-rbuilder/node/Cargo.toml @@ -0,0 +1,40 @@ +[package] +name = "op-rbuilder-node-optimism" +edition = "2021" + +[dependencies] +# workspace +op-rbuilder-payload-builder = { path = "../payload_builder" } +transaction-pool-bundle-ext = { path = "../../transaction-pool-bundle-ext" } +rbuilder-bundle-pool-operations = { path = "../../transaction-pool-bundle-ext/bundle_pool_ops/rbuilder" } + +# reth +reth-chainspec.workspace = true +reth-payload-builder.workspace = true +reth-primitives.workspace = true +reth-basic-payload-builder.workspace = true +reth-node-builder.workspace = true +reth-tracing.workspace = true +reth-provider.workspace = true +reth-transaction-pool.workspace = true +reth-evm.workspace = true +reth-evm-optimism.workspace = true +reth-node-optimism = { workspace = true } + +# async +tracing.workspace = true + +# misc +clap.workspace = true +eyre.workspace = true + +[features] +optimism = [ + "reth-node-optimism/optimism", + "reth-chainspec/optimism", + "reth-provider/optimism", + "reth-evm-optimism/optimism", + "op-rbuilder-payload-builder/optimism", + "rbuilder-bundle-pool-operations/optimism", + "reth-primitives/optimism" +] diff --git a/crates/op-rbuilder/node/src/args.rs b/crates/op-rbuilder/node/src/args.rs new file mode 100644 index 00000000..c0ea455a --- /dev/null +++ b/crates/op-rbuilder/node/src/args.rs @@ -0,0 +1,155 @@ +//! Additional Node command arguments. +//! +//! Copied from OptimismNode to allow easy extension. + +//! clap [Args](clap::Args) for optimism rollup configuration + +use std::path::PathBuf; + +/// Parameters for rollup configuration +#[derive(Debug, Clone, Default, PartialEq, Eq, clap::Args)] +#[command(next_help_heading = "Rollup")] +pub struct OpRbuilderArgs { + /// HTTP endpoint for the sequencer mempool + #[arg(long = "rollup.sequencer-http", value_name = "HTTP_URL")] + pub sequencer_http: Option, + + /// Disable transaction pool gossip + #[arg(long = "rollup.disable-tx-pool-gossip")] + pub disable_txpool_gossip: bool, + + /// Enable walkback to genesis on startup. This is useful for re-validating the existing DB + /// prior to beginning normal syncing. + #[arg(long = "rollup.enable-genesis-walkback")] + pub enable_genesis_walkback: bool, + + /// By default the pending block equals the latest block + /// to save resources and not leak txs from the tx-pool, + /// this flag enables computing of the pending block + /// from the tx-pool instead. + /// + /// If `compute_pending_block` is not enabled, the payload builder + /// will use the payload attributes from the latest block. Note + /// that this flag is not yet functional. + #[arg(long = "rollup.compute-pending-block")] + pub compute_pending_block: bool, + + /// enables discovery v4 if provided + #[arg(long = "rollup.discovery.v4", default_value = "false")] + pub discovery_v4: bool, + + /// Enable the engine2 experimental features on op-reth binary + #[arg(long = "engine.experimental", default_value = "false")] + pub experimental: bool, + + /// Enable the engine2 experimental features on op-reth binary + #[arg(long = "rbuilder.config")] + pub rbuilder_config_path: PathBuf, +} + +#[cfg(test)] +mod tests { + use super::*; + use clap::{Args, Parser}; + + /// A helper type to parse Args more easily + #[derive(Parser)] + struct CommandParser { + #[command(flatten)] + args: T, + } + + #[test] + fn test_parse_optimism_default_args() { + let default_args = OpRbuilderArgs::default(); + let args = CommandParser::::parse_from(["reth"]).args; + assert_eq!(args, default_args); + } + + #[test] + fn test_parse_optimism_walkback_args() { + let expected_args = OpRbuilderArgs { + enable_genesis_walkback: true, + ..Default::default() + }; + let args = CommandParser::::parse_from([ + "reth", + "--rollup.enable-genesis-walkback", + ]) + .args; + assert_eq!(args, expected_args); + } + + #[test] + fn test_parse_optimism_compute_pending_block_args() { + let expected_args = OpRbuilderArgs { + compute_pending_block: true, + ..Default::default() + }; + let args = + CommandParser::::parse_from(["reth", "--rollup.compute-pending-block"]) + .args; + assert_eq!(args, expected_args); + } + + #[test] + fn test_parse_optimism_discovery_v4_args() { + let expected_args = OpRbuilderArgs { + discovery_v4: true, + ..Default::default() + }; + let args = + CommandParser::::parse_from(["reth", "--rollup.discovery.v4"]).args; + assert_eq!(args, expected_args); + } + + #[test] + fn test_parse_optimism_sequencer_http_args() { + let expected_args = OpRbuilderArgs { + sequencer_http: Some("http://host:port".into()), + ..Default::default() + }; + let args = CommandParser::::parse_from([ + "reth", + "--rollup.sequencer-http", + "http://host:port", + ]) + .args; + assert_eq!(args, expected_args); + } + + #[test] + fn test_parse_optimism_disable_txpool_args() { + let expected_args = OpRbuilderArgs { + disable_txpool_gossip: true, + ..Default::default() + }; + let args = CommandParser::::parse_from([ + "reth", + "--rollup.disable-tx-pool-gossip", + ]) + .args; + assert_eq!(args, expected_args); + } + + #[test] + fn test_parse_optimism_many_args() { + let expected_args = OpRbuilderArgs { + disable_txpool_gossip: true, + compute_pending_block: true, + enable_genesis_walkback: true, + sequencer_http: Some("http://host:port".into()), + ..Default::default() + }; + let args = CommandParser::::parse_from([ + "reth", + "--rollup.disable-tx-pool-gossip", + "--rollup.compute-pending-block", + "--rollup.enable-genesis-walkback", + "--rollup.sequencer-http", + "http://host:port", + ]) + .args; + assert_eq!(args, expected_args); + } +} diff --git a/crates/op-rbuilder/node/src/lib.rs b/crates/op-rbuilder/node/src/lib.rs new file mode 100644 index 00000000..02f51726 --- /dev/null +++ b/crates/op-rbuilder/node/src/lib.rs @@ -0,0 +1,16 @@ +//! Standalone crate for op-rbuilder-specific Reth configuration and builder types. +//! +//! Inherits Network, Executor, and Consensus Builders from the Optimism defaults, +//! overrides the Pool and Payload Builders. + +#![cfg_attr(all(not(test), feature = "optimism"), warn(unused_crate_dependencies))] +// The `optimism` feature must be enabled to use this crate. +#![cfg(feature = "optimism")] + +use tracing as _; + +/// CLI argument parsing. +pub mod args; + +pub mod node; +pub use node::OpRbuilderNode; diff --git a/crates/op-rbuilder/node/src/node.rs b/crates/op-rbuilder/node/src/node.rs new file mode 100644 index 00000000..47ce9c8f --- /dev/null +++ b/crates/op-rbuilder/node/src/node.rs @@ -0,0 +1,286 @@ +//! op-rbuilder Node types config. +//! +//! Inherits Network, Executor, and Consensus Builders from the optimism node, +//! and overrides the Pool and Payload Builders. + +use rbuilder_bundle_pool_operations::BundlePoolOps; +use reth_basic_payload_builder::{BasicPayloadJobGenerator, BasicPayloadJobGeneratorConfig}; +use reth_chainspec::ChainSpec; +use reth_evm::ConfigureEvm; +use reth_evm_optimism::OptimismEvmConfig; +use reth_node_builder::{ + components::{ComponentsBuilder, PayloadServiceBuilder, PoolBuilder}, + node::{FullNodeTypes, NodeTypes}, + BuilderContext, Node, PayloadBuilderConfig, +}; +use reth_node_optimism::{ + node::{ + OptimismAddOns, OptimismConsensusBuilder, OptimismExecutorBuilder, OptimismNetworkBuilder, + }, + txpool::OpTransactionValidator, + OptimismEngineTypes, +}; +use reth_payload_builder::{PayloadBuilderHandle, PayloadBuilderService}; +use reth_primitives::TransactionSigned; +use reth_provider::CanonStateSubscriptions; +use reth_tracing::tracing::{debug, info}; +use reth_transaction_pool::{ + blobstore::DiskFileBlobStore, CoinbaseTipOrdering, EthPooledTransaction, + TransactionValidationTaskExecutor, +}; +use std::path::PathBuf; +use transaction_pool_bundle_ext::{ + BundlePoolOperations, BundleSupportedPool, TransactionPoolBundleExt, +}; + +use crate::args::OpRbuilderArgs; + +/// Type configuration for an OP rbuilder node. +#[derive(Debug, Default, Clone)] +#[non_exhaustive] +pub struct OpRbuilderNode { + /// Additional args + pub args: OpRbuilderArgs, +} + +impl OpRbuilderNode { + /// Creates a new instance of the OP rbuilder node type. + pub const fn new(args: OpRbuilderArgs) -> Self { + Self { args } + } + + /// Returns the components for the given [`OpRbuilderArgs`]. + pub fn components( + args: OpRbuilderArgs, + ) -> ComponentsBuilder< + Node, + OpRbuilderPoolBuilder, + OpRbuilderPayloadServiceBuilder, + OptimismNetworkBuilder, + OptimismExecutorBuilder, + OptimismConsensusBuilder, + > + where + Node: FullNodeTypes, + { + let OpRbuilderArgs { + disable_txpool_gossip, + compute_pending_block, + discovery_v4, + rbuilder_config_path, + .. + } = args; + ComponentsBuilder::default() + .node_types::() + .pool(OpRbuilderPoolBuilder::new(rbuilder_config_path)) + .payload(OpRbuilderPayloadServiceBuilder::new( + compute_pending_block, + OptimismEvmConfig::default(), + )) + .network(OptimismNetworkBuilder { + disable_txpool_gossip, + disable_discovery_v4: !discovery_v4, + }) + .executor(OptimismExecutorBuilder::default()) + .consensus(OptimismConsensusBuilder::default()) + } +} + +impl Node for OpRbuilderNode +where + N: FullNodeTypes, +{ + type ComponentsBuilder = ComponentsBuilder< + N, + OpRbuilderPoolBuilder, + OpRbuilderPayloadServiceBuilder, + OptimismNetworkBuilder, + OptimismExecutorBuilder, + OptimismConsensusBuilder, + >; + + type AddOns = OptimismAddOns; + + fn components_builder(&self) -> Self::ComponentsBuilder { + let Self { args } = self; + Self::components(args.clone()) + } +} + +impl NodeTypes for OpRbuilderNode { + type Primitives = (); + type Engine = OptimismEngineTypes; + type ChainSpec = ChainSpec; +} + +/// An extended optimism transaction pool with bundle support. +#[derive(Debug, Default, Clone)] +#[non_exhaustive] +pub struct OpRbuilderPoolBuilder { + rbuilder_config_path: PathBuf, +} + +impl OpRbuilderPoolBuilder { + /// Creates a new instance of the OP rbuilder pool builder. + pub fn new(rbuilder_config_path: PathBuf) -> Self { + Self { + rbuilder_config_path, + } + } +} + +pub type OpRbuilderTransactionPool = BundleSupportedPool< + TransactionValidationTaskExecutor>, + CoinbaseTipOrdering, + S, + BundlePoolOps, +>; + +impl PoolBuilder for OpRbuilderPoolBuilder +where + Node: FullNodeTypes, +{ + type Pool = OpRbuilderTransactionPool; + + async fn build_pool(self, ctx: &BuilderContext) -> eyre::Result { + let data_dir = ctx.config().datadir(); + let blob_store = DiskFileBlobStore::open(data_dir.blobstore(), Default::default())?; + + let validator = TransactionValidationTaskExecutor::eth_builder(ctx.chain_spec()) + .with_head_timestamp(ctx.head().timestamp) + .kzg_settings(ctx.kzg_settings()?) + .with_additional_tasks(ctx.config().txpool.additional_validation_tasks) + .build_with_tasks( + ctx.provider().clone(), + ctx.task_executor().clone(), + blob_store.clone(), + ) + .map(|validator| { + OpTransactionValidator::new(validator) + // In --dev mode we can't require gas fees because we're unable to decode the L1 + // block info + .require_l1_data_gas_fee(!ctx.config().dev.dev) + }); + + let bundle_ops = BundlePoolOps::new(ctx.provider().clone(), self.rbuilder_config_path) + .await + .expect("Failed to instantiate RbuilderBundlePoolOps"); + let transaction_pool = OpRbuilderTransactionPool::new( + validator, + CoinbaseTipOrdering::default(), + blob_store, + bundle_ops, + ctx.pool_config(), + ); + + info!(target: "reth::cli", "Transaction pool initialized"); + let transactions_path = data_dir.txpool_transactions(); + + // spawn txpool maintenance task + { + let pool = transaction_pool.clone(); + let chain_events = ctx.provider().canonical_state_stream(); + let client = ctx.provider().clone(); + let transactions_backup_config = + reth_transaction_pool::maintain::LocalTransactionBackupConfig::with_local_txs_backup(transactions_path); + + ctx.task_executor() + .spawn_critical_with_graceful_shutdown_signal( + "local transactions backup task", + |shutdown| { + reth_transaction_pool::maintain::backup_local_transactions_task( + shutdown, + pool.clone(), + transactions_backup_config, + ) + }, + ); + + // spawn the maintenance task + ctx.task_executor().spawn_critical( + "txpool maintenance task", + reth_transaction_pool::maintain::maintain_transaction_pool_future( + client, + pool, + chain_events, + ctx.task_executor().clone(), + Default::default(), + ), + ); + debug!(target: "reth::cli", "Spawned txpool maintenance task"); + } + + Ok(transaction_pool) + } +} + +/// A op-rbuilder payload service builder +#[derive(Debug, Default, Clone)] +pub struct OpRbuilderPayloadServiceBuilder { + /// By default the pending block equals the latest block + /// to save resources and not leak txs from the tx-pool, + /// this flag enables computing of the pending block + /// from the tx-pool instead. + /// + /// If `compute_pending_block` is not enabled, the payload builder + /// will use the payload attributes from the latest block. Note + /// that this flag is not yet functional. + pub compute_pending_block: bool, + /// The EVM configuration to use for the payload builder. + pub evm_config: EVM, +} + +impl OpRbuilderPayloadServiceBuilder { + /// Create a new instance with the given `compute_pending_block` flag and evm config. + pub const fn new(compute_pending_block: bool, evm_config: EVM) -> Self { + Self { + compute_pending_block, + evm_config, + } + } +} + +impl PayloadServiceBuilder for OpRbuilderPayloadServiceBuilder +where + Node: FullNodeTypes, + Pool: TransactionPoolBundleExt + + BundlePoolOperations + + Unpin + + 'static, + EVM: ConfigureEvm, +{ + async fn spawn_payload_service( + self, + ctx: &BuilderContext, + pool: Pool, + ) -> eyre::Result> { + let payload_builder = op_rbuilder_payload_builder::OpRbuilderPayloadBuilder::new( + OptimismEvmConfig::default(), + ) + .set_compute_pending_block(self.compute_pending_block); + let conf = ctx.payload_builder_config(); + + let payload_job_config = BasicPayloadJobGeneratorConfig::default() + .interval(conf.interval()) + .deadline(conf.deadline()) + .max_payload_tasks(conf.max_payload_tasks()) + // no extradata for OP + .extradata(Default::default()); + + let payload_generator = BasicPayloadJobGenerator::with_builder( + ctx.provider().clone(), + pool, + ctx.task_executor().clone(), + payload_job_config, + ctx.chain_spec(), + payload_builder, + ); + let (payload_service, payload_builder) = + PayloadBuilderService::new(payload_generator, ctx.provider().canonical_state_stream()); + + ctx.task_executor() + .spawn_critical("payload builder service", Box::pin(payload_service)); + + Ok(payload_builder) + } +} diff --git a/crates/op-rbuilder/payload_builder/Cargo.toml b/crates/op-rbuilder/payload_builder/Cargo.toml new file mode 100644 index 00000000..ca4e1ca6 --- /dev/null +++ b/crates/op-rbuilder/payload_builder/Cargo.toml @@ -0,0 +1,44 @@ +[package] +name = "op-rbuilder-payload-builder" +version = "0.1.0" +edition = "2021" +description = "A payload builder for op-rbuilder with bundle support." + +[dependencies] +# workspace +transaction-pool-bundle-ext = { path = "../../transaction-pool-bundle-ext" } + +# reth +reth-chainspec.workspace = true +reth-primitives.workspace = true +reth-revm.workspace = true +reth-rpc-types.workspace = true +reth-provider.workspace = true +reth-evm.workspace = true +reth-evm-optimism.workspace = true +reth-node-optimism.workspace = true +reth-execution-types.workspace = true +reth-payload-builder.workspace = true +reth-basic-payload-builder.workspace = true +reth-trie.workspace = true +reth-chain-state.workspace = true +reth-optimism-payload-builder.workspace = true + +# ethereum +revm.workspace = true + +# misc +tracing.workspace = true + +[features] +optimism = [ + "reth-chainspec/optimism", + "reth-primitives/optimism", + "reth-provider/optimism", + "reth-node-optimism/optimism", + "reth-evm-optimism/optimism", + "reth-revm/optimism", + "reth-execution-types/optimism", + "reth-optimism-payload-builder/optimism", + "revm/optimism" +] diff --git a/crates/op-rbuilder/payload_builder/src/builder.rs b/crates/op-rbuilder/payload_builder/src/builder.rs new file mode 100644 index 00000000..a00db5e6 --- /dev/null +++ b/crates/op-rbuilder/payload_builder/src/builder.rs @@ -0,0 +1,690 @@ +//! Optimism payload builder implementation with Flashbots bundle support. + +use reth_basic_payload_builder::*; +use reth_chain_state::ExecutedBlock; +use reth_chainspec::{EthereumHardforks, OptimismHardfork}; +use reth_evm::{system_calls::pre_block_beacon_root_contract_call, ConfigureEvm}; +use reth_execution_types::ExecutionOutcome; +use reth_node_optimism::{OptimismBuiltPayload, OptimismPayloadBuilderAttributes}; +use reth_optimism_payload_builder::error::OptimismPayloadBuilderError; +use reth_payload_builder::error::PayloadBuilderError; +use reth_primitives::{ + constants::{BEACON_NONCE, EMPTY_RECEIPTS, EMPTY_TRANSACTIONS}, + eip4844::calculate_excess_blob_gas, + proofs, Block, Header, Receipt, TransactionSigned, TxType, EMPTY_OMMER_ROOT_HASH, U256, +}; +use reth_provider::StateProviderFactory; +use reth_revm::database::StateProviderDatabase; +use reth_rpc_types::{ + beacon::events::{PayloadAttributesData, PayloadAttributesEvent}, + engine::PayloadAttributes, +}; +use reth_trie::HashedPostState; +use revm::{ + db::states::bundle_state::BundleRetention, + primitives::{EVMError, EnvWithHandlerCfg, InvalidTransaction, ResultAndState}, + DatabaseCommit, State, +}; +use std::sync::Arc; +use tracing::{debug, error, trace, warn}; +use transaction_pool_bundle_ext::{BundlePoolOperations, TransactionPoolBundleExt}; + +/// Payload builder for OP Stack, which includes bundle support. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct OpRbuilderPayloadBuilder { + /// The rollup's compute pending block configuration option. + compute_pending_block: bool, + /// The type responsible for creating the evm. + evm_config: EvmConfig, +} + +impl OpRbuilderPayloadBuilder { + pub const fn new(evm_config: EvmConfig) -> Self { + Self { + compute_pending_block: true, + evm_config, + } + } + + /// Sets the rollup's compute pending block configuration option. + pub const fn set_compute_pending_block(mut self, compute_pending_block: bool) -> Self { + self.compute_pending_block = compute_pending_block; + self + } + + /// Enables the rollup's compute pending block configuration option. + pub const fn compute_pending_block(self) -> Self { + self.set_compute_pending_block(true) + } + + /// Returns the rollup's compute pending block configuration option. + pub const fn is_compute_pending_block(&self) -> bool { + self.compute_pending_block + } +} + +/// Implementation of the [`PayloadBuilder`] trait for [`OpRbuilderPayloadBuilder`]. +impl PayloadBuilder for OpRbuilderPayloadBuilder +where + Client: StateProviderFactory, + EvmConfig: ConfigureEvm, + Pool: TransactionPoolBundleExt + BundlePoolOperations, +{ + type Attributes = OptimismPayloadBuilderAttributes; + type BuiltPayload = OptimismBuiltPayload; + + fn try_build( + &self, + args: BuildArguments, + ) -> Result, PayloadBuilderError> { + let parent_block = args.config.parent_block.clone(); + // Notify our BundleOperations of the new bundle. + let eth_payload_attributes = args.config.attributes.payload_attributes.clone(); + let payload_attributes = PayloadAttributes { + timestamp: eth_payload_attributes.timestamp, + prev_randao: eth_payload_attributes.prev_randao, + withdrawals: Some(eth_payload_attributes.withdrawals.into_inner()), + parent_beacon_block_root: eth_payload_attributes.parent_beacon_block_root, + suggested_fee_recipient: eth_payload_attributes.suggested_fee_recipient, + }; + let payload_attributes_data = PayloadAttributesData { + parent_block_number: parent_block.number, + parent_block_root: parent_block.header.hash(), + parent_block_hash: parent_block.hash(), + proposal_slot: parent_block.number + 1, + proposer_index: 0, // Shouldn't be required for core building logic + payload_attributes, + }; + let payload_attributes_event = PayloadAttributesEvent { + version: "placeholder".to_string(), + data: payload_attributes_data, + }; + + if let Err(e) = args.pool.notify_payload_attributes_event( + payload_attributes_event, + args.config.attributes.gas_limit, + ) { + error!(?e, "Failed to notify payload attributes event!"); + }; + try_build_inner(self.evm_config.clone(), args, self.compute_pending_block) + } + + fn on_missing_payload( + &self, + _args: BuildArguments, + ) -> MissingPayloadBehaviour { + // we want to await the job that's already in progress because that should be returned as + // is, there's no benefit in racing another job + MissingPayloadBehaviour::AwaitInProgress + } + + fn build_empty_payload( + &self, + client: &Client, + config: PayloadConfig, + ) -> Result { + let extra_data = config.extra_data(); + let PayloadConfig { + initialized_block_env, + parent_block, + attributes, + chain_spec, + .. + } = config; + + debug!(target: "payload_builder", parent_hash = ?parent_block.hash(), parent_number = parent_block.number, "building empty payload"); + + let state = client.state_by_block_hash(parent_block.hash()).map_err(|err| { + warn!(target: "payload_builder", parent_hash=%parent_block.hash(), %err, "failed to get state for empty payload"); + err + })?; + let mut db = State::builder() + .with_database(StateProviderDatabase::new(state)) + .with_bundle_update() + .build(); + + let base_fee = initialized_block_env.basefee.to::(); + let block_gas_limit: u64 = initialized_block_env + .gas_limit + .try_into() + .unwrap_or(chain_spec.max_gas_limit); + + let WithdrawalsOutcome { + withdrawals_root, + withdrawals, + } = commit_withdrawals( + &mut db, + &chain_spec, + attributes.payload_attributes.timestamp, + attributes.payload_attributes.withdrawals.clone(), + ) + .map_err(|err| { + warn!(target: "payload_builder", + parent_hash=%parent_block.hash(), + %err, + "failed to commit withdrawals for empty payload" + ); + err + })?; + + // merge all transitions into bundle state, this would apply the withdrawal balance + // changes and 4788 contract call + db.merge_transitions(BundleRetention::PlainState); + + // calculate the state root + let bundle_state = db.take_bundle(); + let hashed_state = HashedPostState::from_bundle_state(&bundle_state.state); + let state_root = db.database.state_root(hashed_state).map_err(|err| { + warn!(target: "payload_builder", + parent_hash=%parent_block.hash(), + %err, + "failed to calculate state root for empty payload" + ); + err + })?; + + let mut excess_blob_gas = None; + let mut blob_gas_used = None; + + if chain_spec.is_cancun_active_at_timestamp(attributes.payload_attributes.timestamp) { + excess_blob_gas = if chain_spec.is_cancun_active_at_timestamp(parent_block.timestamp) { + let parent_excess_blob_gas = parent_block.excess_blob_gas.unwrap_or_default(); + let parent_blob_gas_used = parent_block.blob_gas_used.unwrap_or_default(); + Some(calculate_excess_blob_gas( + parent_excess_blob_gas, + parent_blob_gas_used, + )) + } else { + // for the first post-fork block, both parent.blob_gas_used and + // parent.excess_blob_gas are evaluated as 0 + Some(calculate_excess_blob_gas(0, 0)) + }; + + blob_gas_used = Some(0); + } + let header = Header { + parent_hash: parent_block.hash(), + ommers_hash: EMPTY_OMMER_ROOT_HASH, + beneficiary: initialized_block_env.coinbase, + state_root, + transactions_root: EMPTY_TRANSACTIONS, + withdrawals_root, + receipts_root: EMPTY_RECEIPTS, + logs_bloom: Default::default(), + timestamp: attributes.payload_attributes.timestamp, + mix_hash: attributes.payload_attributes.prev_randao, + nonce: BEACON_NONCE, + base_fee_per_gas: Some(base_fee), + number: parent_block.number + 1, + gas_limit: block_gas_limit, + difficulty: U256::ZERO, + gas_used: 0, + extra_data, + blob_gas_used, + excess_blob_gas, + parent_beacon_block_root: attributes.payload_attributes.parent_beacon_block_root, + requests_root: None, + }; + + let block = Block { + header, + body: vec![], + ommers: vec![], + withdrawals, + requests: None, + }; + let sealed_block = block.seal_slow(); + + Ok(OptimismBuiltPayload::new( + attributes.payload_attributes.payload_id(), + sealed_block, + U256::ZERO, + chain_spec, + attributes, + None, + )) + } +} + +/// Constructs an Optimism payload from the transactions sent through the +/// Payload attributes by the sequencer, and bundles returned by the BundlePool. +/// +/// Given build arguments including an Ethereum client, bundle-enabled transaction pool, +/// and configuration, this function creates a transaction payload. Returns +/// a result indicating success with the payload or an error in case of failure. +#[inline] +pub(crate) fn try_build_inner( + evm_config: EvmConfig, + args: BuildArguments, + _compute_pending_block: bool, +) -> Result, PayloadBuilderError> +where + EvmConfig: ConfigureEvm, + Client: StateProviderFactory, + Pool: TransactionPoolBundleExt + BundlePoolOperations, +{ + let BuildArguments { + client, + pool, + mut cached_reads, + config, + cancel, + best_payload, + } = args; + + let state_provider = client.state_by_block_hash(config.parent_block.hash())?; + let state = StateProviderDatabase::new(state_provider); + let mut db = State::builder() + .with_database_ref(cached_reads.as_db(state)) + .with_bundle_update() + .build(); + let extra_data = config.extra_data(); + let PayloadConfig { + initialized_block_env, + initialized_cfg, + parent_block, + attributes, + chain_spec, + .. + } = config; + + debug!(target: "payload_builder", id=%attributes.payload_attributes.payload_id(), parent_hash = ?parent_block.hash(), parent_number = parent_block.number, "building new payload"); + + let mut cumulative_gas_used = 0; + let block_gas_limit: u64 = attributes.gas_limit.unwrap_or_else(|| { + initialized_block_env + .gas_limit + .try_into() + .unwrap_or(chain_spec.max_gas_limit) + }); + let base_fee = initialized_block_env.basefee.to::(); + + let mut executed_txs = Vec::with_capacity(attributes.transactions.len()); + let mut executed_senders = Vec::with_capacity(attributes.transactions.len()); + + let mut total_fees = U256::ZERO; + + let block_number = initialized_block_env.number.to::(); + + let is_regolith = chain_spec.is_fork_active_at_timestamp( + OptimismHardfork::Regolith, + attributes.payload_attributes.timestamp, + ); + + // apply eip-4788 pre block contract call + pre_block_beacon_root_contract_call( + &mut db, + &evm_config, + &chain_spec, + &initialized_cfg, + &initialized_block_env, + attributes.payload_attributes.parent_beacon_block_root, + ) + .map_err(|err| { + warn!(target: "payload_builder", + parent_hash=%parent_block.hash(), + %err, + "failed to apply beacon root contract call for empty payload" + ); + PayloadBuilderError::Internal(err.into()) + })?; + + // Ensure that the create2deployer is force-deployed at the canyon transition. Optimism + // blocks will always have at least a single transaction in them (the L1 info transaction), + // so we can safely assume that this will always be triggered upon the transition and that + // the above check for empty blocks will never be hit on OP chains. + reth_evm_optimism::ensure_create2_deployer( + chain_spec.clone(), + attributes.payload_attributes.timestamp, + &mut db, + ) + .map_err(|err| { + warn!(target: "payload_builder", %err, "missing create2 deployer, skipping block."); + PayloadBuilderError::other(OptimismPayloadBuilderError::ForceCreate2DeployerFail) + })?; + + let mut receipts = Vec::with_capacity(attributes.transactions.len()); + for sequencer_tx in &attributes.transactions { + // Check if the job was cancelled, if so we can exit early. + if cancel.is_cancelled() { + return Ok(BuildOutcome::Cancelled); + } + + // A sequencer's block should never contain blob transactions. + if sequencer_tx.value().is_eip4844() { + return Err(PayloadBuilderError::other( + OptimismPayloadBuilderError::BlobTransactionRejected, + )); + } + + // Convert the transaction to a [TransactionSignedEcRecovered]. This is + // purely for the purposes of utilizing the `evm_config.tx_env`` function. + // Deposit transactions do not have signatures, so if the tx is a deposit, this + // will just pull in its `from` address. + let sequencer_tx = sequencer_tx + .value() + .clone() + .try_into_ecrecovered() + .map_err(|_| { + PayloadBuilderError::other(OptimismPayloadBuilderError::TransactionEcRecoverFailed) + })?; + + // Cache the depositor account prior to the state transition for the deposit nonce. + // + // Note that this *only* needs to be done post-regolith hardfork, as deposit nonces + // were not introduced in Bedrock. In addition, regular transactions don't have deposit + // nonces, so we don't need to touch the DB for those. + let depositor = (is_regolith && sequencer_tx.is_deposit()) + .then(|| { + db.load_cache_account(sequencer_tx.signer()) + .map(|acc| acc.account_info().unwrap_or_default()) + }) + .transpose() + .map_err(|_| { + PayloadBuilderError::other(OptimismPayloadBuilderError::AccountLoadFailed( + sequencer_tx.signer(), + )) + })?; + + let env = EnvWithHandlerCfg::new_with_cfg_env( + initialized_cfg.clone(), + initialized_block_env.clone(), + evm_config.tx_env(&sequencer_tx), + ); + + let mut evm = evm_config.evm_with_env(&mut db, env); + + let ResultAndState { result, state } = match evm.transact() { + Ok(res) => res, + Err(err) => { + match err { + EVMError::Transaction(err) => { + trace!(target: "payload_builder", %err, ?sequencer_tx, "Error in sequencer transaction, skipping."); + continue; + } + err => { + // this is an error that we should treat as fatal for this attempt + return Err(PayloadBuilderError::EvmExecutionError(err)); + } + } + } + }; + + // to release the db reference drop evm. + drop(evm); + // commit changes + db.commit(state); + + let gas_used = result.gas_used(); + + // add gas used by the transaction to cumulative gas used, before creating the receipt + cumulative_gas_used += gas_used; + + // Push transaction changeset and calculate header bloom filter for receipt. + receipts.push(Some(Receipt { + tx_type: sequencer_tx.tx_type(), + success: result.is_success(), + cumulative_gas_used, + logs: result.into_logs().into_iter().map(Into::into).collect(), + deposit_nonce: depositor.map(|account| account.nonce), + // The deposit receipt version was introduced in Canyon to indicate an update to how + // receipt hashes should be computed when set. The state transition process + // ensures this is only set for post-Canyon deposit transactions. + deposit_receipt_version: chain_spec + .is_fork_active_at_timestamp( + OptimismHardfork::Canyon, + attributes.payload_attributes.timestamp, + ) + .then_some(1), + })); + + // append sender and transaction to the respective lists + executed_senders.push(sequencer_tx.signer()); + executed_txs.push(sequencer_tx.into_signed()); + } + + // Apply rbuilder block + let mut count = 0; + let iter = pool + .get_transactions(U256::from(parent_block.number + 1)) + .unwrap() + .into_iter(); + for pool_tx in iter { + // Ensure we still have capacity for this transaction + if cumulative_gas_used + pool_tx.gas_limit() > block_gas_limit { + let inner = + EVMError::Custom("rbuilder suggested transaction over gas limit!".to_string()); + return Err(PayloadBuilderError::EvmExecutionError(inner)); + } + + // A sequencer's block should never contain blob or deposit transactions from rbuilder. + if pool_tx.is_eip4844() || pool_tx.tx_type() == TxType::Deposit as u8 { + error!("rbuilder suggested blob or deposit transaction!"); + let inner = + EVMError::Custom("rbuilder suggested blob or deposit transaction!".to_string()); + return Err(PayloadBuilderError::EvmExecutionError(inner)); + } + + // check if the job was cancelled, if so we can exit early + if cancel.is_cancelled() { + return Ok(BuildOutcome::Cancelled); + } + + // convert tx to a signed transaction + let tx = pool_tx.try_into_ecrecovered().map_err(|_| { + PayloadBuilderError::other(OptimismPayloadBuilderError::TransactionEcRecoverFailed) + })?; + + let env = EnvWithHandlerCfg::new_with_cfg_env( + initialized_cfg.clone(), + initialized_block_env.clone(), + evm_config.tx_env(&tx), + ); + + // Configure the environment for the block. + let mut evm = evm_config.evm_with_env(&mut db, env); + + let ResultAndState { result, state } = match evm.transact() { + Ok(res) => res, + Err(err) => { + match err { + EVMError::Transaction(err) => { + if matches!(err, InvalidTransaction::NonceTooLow { .. }) { + // if the nonce is too low, we can skip this transaction + error!(target: "payload_builder", %err, ?tx, "skipping nonce too low transaction"); + } else { + // if the transaction is invalid, we can skip it and all of its + // descendants + error!(target: "payload_builder", %err, ?tx, "skipping invalid transaction and its descendants"); + } + + let inner = EVMError::Custom("rbuilder transaction errored!".to_string()); + return Err(PayloadBuilderError::EvmExecutionError(inner)); + } + err => { + // this is an error that we should treat as fatal for this attempt + error!("rbuilder provided where an error occured!"); + return Err(PayloadBuilderError::EvmExecutionError(err)); + } + } + } + }; + // drop evm so db is released. + drop(evm); + // commit changes + db.commit(state); + + let gas_used = result.gas_used(); + + // add gas used by the transaction to cumulative gas used, before creating the + // receipt + cumulative_gas_used += gas_used; + + // Push transaction changeset and calculate header bloom filter for receipt. + receipts.push(Some(Receipt { + tx_type: tx.tx_type(), + success: result.is_success(), + cumulative_gas_used, + logs: result.into_logs().into_iter().map(Into::into).collect(), + deposit_nonce: None, + deposit_receipt_version: None, + })); + + // update add to total fees + let miner_fee = tx + .effective_tip_per_gas(Some(base_fee)) + .expect("fee is always valid; execution succeeded"); + total_fees += U256::from(miner_fee) * U256::from(gas_used); + + // append sender and transaction to the respective lists + executed_senders.push(tx.signer()); + executed_txs.push(tx.clone().into_signed()); + count += 1; + } + + trace!("Executed {} txns from rbuilder", count); + + // check if we have a better block + if !is_better_payload(best_payload.as_ref(), total_fees) { + // can skip building the block + return Ok(BuildOutcome::Aborted { + fees: total_fees, + cached_reads, + }); + } + + let WithdrawalsOutcome { + withdrawals_root, + withdrawals, + } = commit_withdrawals( + &mut db, + &chain_spec, + attributes.payload_attributes.timestamp, + attributes.clone().payload_attributes.withdrawals, + )?; + + // merge all transitions into bundle state, this would apply the withdrawal balance changes + // and 4788 contract call + db.merge_transitions(BundleRetention::PlainState); + + let execution_outcome = ExecutionOutcome::new( + db.take_bundle(), + vec![receipts].into(), + block_number, + Vec::new(), + ); + let receipts_root = execution_outcome + .optimism_receipts_root_slow( + block_number, + chain_spec.as_ref(), + attributes.payload_attributes.timestamp, + ) + .expect("Number is in range"); + let logs_bloom = execution_outcome + .block_logs_bloom(block_number) + .expect("Number is in range"); + + // calculate the state root + let hashed_state = HashedPostState::from_bundle_state(&execution_outcome.state().state); + let (state_root, trie_output) = { + let state_provider = db.database.0.inner.borrow_mut(); + state_provider + .db + .state_root_with_updates(hashed_state.clone()) + .inspect_err(|err| { + warn!(target: "payload_builder", + parent_hash=%parent_block.hash(), + %err, + "failed to calculate state root for empty payload" + ); + })? + }; + + // create the block header + let transactions_root = proofs::calculate_transaction_root(&executed_txs); + + // initialize empty blob sidecars. There are no blob transactions on L2. + let blob_sidecars = Vec::new(); + let mut excess_blob_gas = None; + let mut blob_gas_used = None; + + // only determine cancun fields when active + if chain_spec.is_cancun_active_at_timestamp(attributes.payload_attributes.timestamp) { + excess_blob_gas = if chain_spec.is_cancun_active_at_timestamp(parent_block.timestamp) { + let parent_excess_blob_gas = parent_block.excess_blob_gas.unwrap_or_default(); + let parent_blob_gas_used = parent_block.blob_gas_used.unwrap_or_default(); + Some(calculate_excess_blob_gas( + parent_excess_blob_gas, + parent_blob_gas_used, + )) + } else { + // for the first post-fork block, both parent.blob_gas_used and + // parent.excess_blob_gas are evaluated as 0 + Some(calculate_excess_blob_gas(0, 0)) + }; + + blob_gas_used = Some(0); + } + + let header = Header { + parent_hash: parent_block.hash(), + ommers_hash: EMPTY_OMMER_ROOT_HASH, + beneficiary: initialized_block_env.coinbase, + state_root, + transactions_root, + receipts_root, + withdrawals_root, + logs_bloom, + timestamp: attributes.payload_attributes.timestamp, + mix_hash: attributes.payload_attributes.prev_randao, + nonce: BEACON_NONCE, + base_fee_per_gas: Some(base_fee), + number: parent_block.number + 1, + gas_limit: block_gas_limit, + difficulty: U256::ZERO, + gas_used: cumulative_gas_used, + extra_data, + parent_beacon_block_root: attributes.payload_attributes.parent_beacon_block_root, + blob_gas_used, + excess_blob_gas, + requests_root: None, + }; + + // seal the block + let block = Block { + header, + body: executed_txs, + ommers: vec![], + withdrawals, + requests: None, + }; + + let sealed_block = block.seal_slow(); + debug!(target: "payload_builder", ?sealed_block, "sealed built block"); + + // create the executed block data + let executed = ExecutedBlock { + block: Arc::new(sealed_block.clone()), + senders: Arc::new(executed_senders), + execution_output: Arc::new(execution_outcome), + hashed_state: Arc::new(hashed_state), + trie: Arc::new(trie_output), + }; + + let mut payload = OptimismBuiltPayload::new( + attributes.payload_attributes.id, + sealed_block, + total_fees, + chain_spec, + attributes, + Some(executed), + ); + + // extend the payload with the blob sidecars from the executed txs + payload.extend_sidecars(blob_sidecars); + + Ok(BuildOutcome::Better { + payload, + cached_reads, + }) +} diff --git a/crates/op-rbuilder/payload_builder/src/lib.rs b/crates/op-rbuilder/payload_builder/src/lib.rs new file mode 100644 index 00000000..8edcda43 --- /dev/null +++ b/crates/op-rbuilder/payload_builder/src/lib.rs @@ -0,0 +1,8 @@ +//! Payload builder for the op-rbuilder with bundle support. + +#![cfg_attr(all(not(test), feature = "optimism"), warn(unused_crate_dependencies))] +// The `optimism` feature must be enabled to use this crate. +#![cfg(feature = "optimism")] + +pub mod builder; +pub use builder::OpRbuilderPayloadBuilder; diff --git a/crates/op-rbuilder/src/eth_bundle_api.rs b/crates/op-rbuilder/src/eth_bundle_api.rs new file mode 100644 index 00000000..2beb28e4 --- /dev/null +++ b/crates/op-rbuilder/src/eth_bundle_api.rs @@ -0,0 +1,80 @@ +//! An implemention of the *internal* eth_sendBundle api used by rbuilder. +//! +//! Should be refactored into standalone crate if required by other code. + +use jsonrpsee::{ + proc_macros::rpc, + types::{ErrorCode, ErrorObjectOwned}, +}; +use rbuilder::{ + live_builder::order_input::rpc_server::RawCancelBundle, + primitives::{ + serialize::{RawBundle, TxEncoding}, + Bundle, + }, +}; +use tracing::warn; +use transaction_pool_bundle_ext::BundlePoolOperations; + +/// [`EthBundleApiServer`] implementation. +pub struct EthBundleMinimalApi { + pool: BundlePool, +} + +impl EthBundleMinimalApi { + pub fn new(pool: BundlePool) -> Self { + Self { pool } + } +} + +#[async_trait::async_trait] +impl EthCallBundleMinimalApiServer for EthBundleMinimalApi +where + BundlePool: + BundlePoolOperations + Clone + 'static, +{ + fn send_bundle(&self, raw_bundle: RawBundle) -> jsonrpsee::core::RpcResult<()> { + let bundle = match raw_bundle.try_into(TxEncoding::WithBlobData) { + Ok(bundle) => bundle, + Err(err) => { + return Err(ErrorObjectOwned::owned( + ErrorCode::InvalidParams.code(), + format!("Failed to parse bundle: {:?}", err), + None::<()>, + )); + } + }; + tokio::task::spawn_local({ + let pool = self.pool.clone(); + async move { + if let Err(e) = pool.add_bundle(bundle).await { + warn!(?e, "Failed to send bundle"); + } + } + }); + Ok(()) + } + + fn cancel_bundle(&self, request: RawCancelBundle) -> jsonrpsee::core::RpcResult<()> { + // Following rbuilder behavior to ignore errors + tokio::task::spawn_local({ + let pool = self.pool.clone(); + async move { + if let Err(e) = pool.cancel_bundle(request).await { + warn!(?e, "Failed to cancel bundle"); + } + } + }); + Ok(()) + } +} + +/// A subset of the *internal* eth_sendBundle api used by rbuilder. +#[rpc(server, namespace = "eth")] +pub trait EthCallBundleMinimalApi { + #[method(name = "sendBundle")] + fn send_bundle(&self, bundle: RawBundle) -> jsonrpsee::core::RpcResult<()>; + + #[method(name = "cancelBundle")] + fn cancel_bundle(&self, request: RawCancelBundle) -> jsonrpsee::core::RpcResult<()>; +} diff --git a/crates/op-rbuilder/src/main.rs b/crates/op-rbuilder/src/main.rs new file mode 100644 index 00000000..3350d78e --- /dev/null +++ b/crates/op-rbuilder/src/main.rs @@ -0,0 +1,84 @@ +//! The main entry point for `op-rbuilder`. +//! +//! `op-rbuilder` is an OP Stack EL client with block building capabilities, powered by in-process +//! rbuilder. +//! +//! The primary difference between `op-rbuilder` and `op-reth` is the `PayloadBuilder` derives +//! transactions exclusively from rbuilder, rather than directly from its transaction pool. +//! +//! ## Usage +//! +//! It has a new mandatory cli arg `--rbuilder.config` which must point to an rbuilder config file. +//! +//! ## Demo +//! +//! Instructions to demo `op-rbuilder` building blocks for an OP L2, and send txns to it with `mev-flood`: +//! +//! 1. Clone [flashbots/optimism](https://github.com/flashbots/optimism) and checkout the +//! `op-rbuilder` branch. +//! 2. `rm` any existing `reth` chain db +//! 3. Run a clean OP stack: `make devnet-clean && make devnet-down && make devnet-up` +//! 4. Run `op-rbuilder` on port 8547: `cargo run --bin op-rbuilder --features "optimism,jemalloc" -- node +//! --chain ../optimism/.devnet/genesis-l2.json --http --http.port 8547 --authrpc.jwtsecret +//! ../optimism/ops-bedrock/test-jwt-secret.txt --rbuilder.config config-optimism-local.toml` +//! 5. Init `mev-flood`: `docker run mevflood init -r http://host.docker.internal:8547 -s local.json` +//! 6. Run `mev-flood`: `docker run --init -v ${PWD}:/app/cli/deployments mevflood spam -p 3 -t 5 -r http://host.docker.internal:8547 -l local.json` +//! +//! Example starting clean OP Stack in one-line: `rm -rf /Users/liamaharon/Library/Application\ Support/reth && cd ../optimism && make devnet-clean && make devnet-down && make devnet-up && cd ../rbuilder && cargo run --bin op-rbuilder --features "optimism,jemalloc" -- node --chain ../optimism/.devnet/genesis-l2.json --http --http.port 8547 --authrpc.jwtsecret ../optimism/ops-bedrock/test-jwt-secret.txt --rbuilder.config config-optimism-local.toml` + +#![cfg_attr(all(not(test), feature = "optimism"), warn(unused_crate_dependencies))] +// The `optimism` feature must be enabled to use this crate. +#![cfg(feature = "optimism")] + +mod eth_bundle_api; + +use crate::eth_bundle_api::EthCallBundleMinimalApiServer; +use clap_builder::Parser; +use eth_bundle_api::EthBundleMinimalApi; +use op_rbuilder_node_optimism::{args::OpRbuilderArgs, OpRbuilderNode}; +use reth::cli::Cli; +use reth_node_optimism::node::OptimismAddOns; +use reth_optimism_rpc::eth::rpc::SequencerClient; +use tracing as _; + +// jemalloc provides better performance +#[cfg(all(feature = "jemalloc", unix))] +#[global_allocator] +static ALLOC: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; + +fn main() { + reth_cli_util::sigsegv_handler::install(); + + if std::env::var_os("RUST_BACKTRACE").is_none() { + std::env::set_var("RUST_BACKTRACE", "1"); + } + + if let Err(err) = Cli::::parse().run(|builder, op_rbuilder_args| async move { + let sequencer_http_arg = op_rbuilder_args.sequencer_http.clone(); + let handle = builder + .with_types::() + .with_components(OpRbuilderNode::components(op_rbuilder_args)) + .with_add_ons::() + .extend_rpc_modules(move |ctx| { + // register sequencer tx forwarder + if let Some(sequencer_http) = sequencer_http_arg { + ctx.registry + .eth_api() + .set_sequencer_client(SequencerClient::new(sequencer_http)); + } + + // register eth bundle api + let ext = EthBundleMinimalApi::new(ctx.registry.pool().clone()); + ctx.modules.merge_configured(ext.into_rpc())?; + + Ok(()) + }) + .launch() + .await?; + + handle.node_exit_future.await + }) { + eprintln!("Error: {err:?}"); + std::process::exit(1); + } +} diff --git a/crates/rbuilder/Cargo.toml b/crates/rbuilder/Cargo.toml index 1bc0ea52..de118f14 100644 --- a/crates/rbuilder/Cargo.toml +++ b/crates/rbuilder/Cargo.toml @@ -7,11 +7,13 @@ build = "build.rs" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +serde = { workspace = true } +serde_json = { workspace = true } tokio.workspace = true -serde = "1.0.188" -serde_json = "1.0.105" -thiserror = "1.0.47" +tokio-stream = { workspace = true } +tokio-util = { workspace = true } eyre.workspace = true +thiserror.workspace = true reth.workspace = true reth-db.workspace = true reth-db-common.workspace = true @@ -57,10 +59,10 @@ ethereum_ssz.workspace = true test_utils = { path = "src/test_utils" } metrics_macros = { path = "src/telemetry/metrics_macros" } -reqwest = { version = "0.11.20", features = ["blocking"] } +reqwest = { workspace = true, features = ["blocking"] } serde_with = { version = "3.8.1", features = ["time_0_3"] } primitive-types = "0.12.1" -url = "2.4.1" +url.workspace = true sqlx = { version = "0.7.1", features = [ "runtime-tokio-native-tls", "postgres", @@ -80,7 +82,6 @@ time = { version = "0.3.36", features = ["macros", "formatting", "parsing"] } bigdecimal = "0.4.1" mempool-dumpster = "0.1.1" itertools = "0.11.0" -tokio-stream = "0.1.14" clap = { workspace = true, features = ["derive", "env"] } priority-queue = "2.0.3" secp256k1 = { version = "0.29", features = [ @@ -97,7 +98,6 @@ ssz_rs = { git = "https://github.com/ralexstokes/ssz-rs.git", version = "0.9.0" beacon-api-client = { git = "https://github.com/ralexstokes/ethereum-consensus/", rev = "cf3c404043230559660810bc0c9d6d5a8498d819" } ethereum-consensus = { git = "https://github.com/ralexstokes/ethereum-consensus/", rev = "cf3c404043230559660810bc0c9d6d5a8498d819" } ssz_rs_derive = { git = "https://github.com/ralexstokes/ssz-rs.git", version = "0.9.0" } -tokio-util = { workspace = true } uuid = { version = "1.6.1", features = ["serde", "v5", "v4"] } prometheus = "0.13.4" hyper = { version = "1.3.1", features = ["server", "full"] } @@ -136,9 +136,20 @@ built = { version = "0.7.1", features = ["git2", "chrono"] } tempfile = "3.8" criterion = { version = "0.5.1", features = ["html_reports", "async_tokio"] } +[features] +optimism = [ + "reth-chainspec/optimism", + "reth-provider/optimism", + "reth/optimism", + "reth-db/optimism", + "reth-node-core/optimism", + "reth-primitives/optimism", + "revm-primitives/optimism", + "revm/optimism" +] +redact-sensitive = [] + [[bench]] name = "bench_main" harness = false -[features] -redact_sensitive = [] diff --git a/crates/rbuilder/src/backtest/fetch/flashbots_db.rs b/crates/rbuilder/src/backtest/fetch/flashbots_db.rs index e6325fff..79106768 100644 --- a/crates/rbuilder/src/backtest/fetch/flashbots_db.rs +++ b/crates/rbuilder/src/backtest/fetch/flashbots_db.rs @@ -1,13 +1,11 @@ -use crate::backtest::BuiltBlockData; -use crate::primitives::OrderId; use crate::{ backtest::{ fetch::data_source::{BlockRef, DataSource, DatasourceData}, - OrdersWithTimestamp, + BuiltBlockData, OrdersWithTimestamp, }, primitives::{ serialize::{RawBundle, RawOrder, RawShareBundle, TxEncoding}, - Order, SimValue, + Order, OrderId, SimValue, }, }; use alloy_primitives::I256; @@ -19,8 +17,7 @@ use bigdecimal::{ use eyre::WrapErr; use reth_primitives::{Bytes, B256, U256, U64}; use sqlx::postgres::PgPool; -use std::collections::HashSet; -use std::{ops::Mul, str::FromStr}; +use std::{collections::HashSet, ops::Mul, str::FromStr}; use time::{OffsetDateTime, PrimitiveDateTime}; use tracing::trace; use uuid::Uuid; diff --git a/crates/rbuilder/src/backtest/fetch/mempool.rs b/crates/rbuilder/src/backtest/fetch/mempool.rs index 25d7202b..c75a30bb 100644 --- a/crates/rbuilder/src/backtest/fetch/mempool.rs +++ b/crates/rbuilder/src/backtest/fetch/mempool.rs @@ -1,9 +1,8 @@ //! Implementation of [`DataSource`] to bring mempool txs from flashbots' mempool dumpster. //! It downloads all the needed parquet files and keeps them cached for future use. -use crate::backtest::fetch::data_source::DatasourceData; use crate::{ backtest::{ - fetch::data_source::{BlockRef, DataSource}, + fetch::data_source::{BlockRef, DataSource, DatasourceData}, OrdersWithTimestamp, }, primitives::{ diff --git a/crates/rbuilder/src/backtest/mod.rs b/crates/rbuilder/src/backtest/mod.rs index 21bfb526..e0b42c9a 100644 --- a/crates/rbuilder/src/backtest/mod.rs +++ b/crates/rbuilder/src/backtest/mod.rs @@ -12,14 +12,13 @@ pub use backtest_build_block::run_backtest_build_block; pub use backtest_build_range::run_backtest_build_range; use std::collections::HashSet; -use crate::primitives::{OrderId, OrderReplacementKey}; -use crate::utils::offset_datetime_to_timestamp_ms; use crate::{ mev_boost::BuilderBlockReceived, primitives::{ serialize::{RawOrder, RawOrderConvertError, TxEncoding}, - AccountNonce, Order, SimValue, + AccountNonce, Order, OrderId, OrderReplacementKey, SimValue, }, + utils::offset_datetime_to_timestamp_ms, }; use alloy_primitives::{Address, TxHash, I256}; use alloy_rpc_types::{BlockTransactions, Transaction}; diff --git a/crates/rbuilder/src/backtest/redistribute/cli/csv_output.rs b/crates/rbuilder/src/backtest/redistribute/cli/csv_output.rs index 8c7cd62e..ee096bfd 100644 --- a/crates/rbuilder/src/backtest/redistribute/cli/csv_output.rs +++ b/crates/rbuilder/src/backtest/redistribute/cli/csv_output.rs @@ -1,8 +1,5 @@ use alloy_primitives::{Address, B256, U256}; -use std::fs::File; -use std::io; -use std::io::Write; -use std::path::Path; +use std::{fs::File, io, io::Write, path::Path}; #[derive(Debug)] pub struct CSVOutputRow { diff --git a/crates/rbuilder/src/backtest/restore_landed_orders/find_landed_orders.rs b/crates/rbuilder/src/backtest/restore_landed_orders/find_landed_orders.rs index ec6c95e6..47a2b136 100644 --- a/crates/rbuilder/src/backtest/restore_landed_orders/find_landed_orders.rs +++ b/crates/rbuilder/src/backtest/restore_landed_orders/find_landed_orders.rs @@ -1,5 +1,7 @@ -use crate::primitives::{Order, OrderId, ShareBundleBody, ShareBundleInner, TxRevertBehavior}; -use crate::utils::get_percent; +use crate::{ + primitives::{Order, OrderId, ShareBundleBody, ShareBundleInner, TxRevertBehavior}, + utils::get_percent, +}; use ahash::HashMap; use alloy_primitives::{B256, I256, U256}; @@ -408,8 +410,10 @@ fn find_landed_order_data( #[cfg(test)] mod tests { use super::*; - use crate::primitives::{Bundle, MempoolTx, Refund, ShareBundle, ShareBundleTx}; - use crate::utils::test_utils::*; + use crate::{ + primitives::{Bundle, MempoolTx, Refund, ShareBundle, ShareBundleTx}, + utils::test_utils::*, + }; fn assert_result( executed_txs: Vec, diff --git a/crates/rbuilder/src/backtest/store.rs b/crates/rbuilder/src/backtest/store.rs index 56f5b02b..4ec5b860 100644 --- a/crates/rbuilder/src/backtest/store.rs +++ b/crates/rbuilder/src/backtest/store.rs @@ -1,17 +1,17 @@ // store orders in the sqlite database -use crate::backtest::BuiltBlockData; -use crate::primitives::OrderId; -use crate::utils::timestamp_ms_to_offset_datetime; use crate::{ - backtest::{BlockData, OrdersWithTimestamp, RawOrdersWithTimestamp}, + backtest::{BlockData, BuiltBlockData, OrdersWithTimestamp, RawOrdersWithTimestamp}, mev_boost::BuilderBlockReceived, - primitives::serialize::{RawOrder, TxEncoding}, + primitives::{ + serialize::{RawOrder, TxEncoding}, + OrderId, + }, + utils::timestamp_ms_to_offset_datetime, }; use ahash::{HashMap, HashSet}; -use alloy_primitives::utils::{ParseUnits, Unit}; use alloy_primitives::{ - utils::{format_ether, parse_ether}, + utils::{format_ether, parse_ether, ParseUnits, Unit}, Address, B256, I256, U256, }; use lz4_flex::{block::DecompressError, compress_prepend_size, decompress_size_prepended}; @@ -20,10 +20,10 @@ use sqlx::{ sqlite::{SqliteConnectOptions, SqliteRow}, ConnectOptions, Connection, Executor, Row, SqliteConnection, }; -use std::str::FromStr; use std::{ ffi::OsString, path::{Path, PathBuf}, + str::FromStr, }; /// Version of the data/format on the DB. diff --git a/crates/rbuilder/src/bin/backtest-distribute.rs b/crates/rbuilder/src/bin/backtest-distribute.rs index 88e73fa6..993d5b67 100644 --- a/crates/rbuilder/src/bin/backtest-distribute.rs +++ b/crates/rbuilder/src/bin/backtest-distribute.rs @@ -1,5 +1,4 @@ -use rbuilder::backtest::redistribute::run_backtest_redistribute; -use rbuilder::live_builder::config::Config; +use rbuilder::{backtest::redistribute::run_backtest_redistribute, live_builder::config::Config}; #[tokio::main] async fn main() -> eyre::Result<()> { diff --git a/crates/rbuilder/src/building/builders/ordering_builder.rs b/crates/rbuilder/src/building/builders/ordering_builder.rs index 80f7b930..55e392c8 100644 --- a/crates/rbuilder/src/building/builders/ordering_builder.rs +++ b/crates/rbuilder/src/building/builders/ordering_builder.rs @@ -5,7 +5,6 @@ //! The described algorithm is ran continuously adding new SimulatedOrders (they arrive on real time!) on each iteration until we run out of time (slot ends). //! Sorting criteria are described on [`Sorting`]. //! For some more details see [`OrderingBuilderConfig`] -use crate::roothash::RootHashConfig; use crate::{ building::{ block_orders_from_sim_orders, @@ -15,6 +14,7 @@ use crate::{ BlockBuildingContext, BlockOrders, ExecutionError, Sorting, }, primitives::{AccountNonce, OrderId}, + roothash::RootHashConfig, }; use ahash::{HashMap, HashSet}; use alloy_primitives::Address; diff --git a/crates/rbuilder/src/building/builders/parallel_builder/block_building_result_assembler.rs b/crates/rbuilder/src/building/builders/parallel_builder/block_building_result_assembler.rs index 857e2755..0728824e 100644 --- a/crates/rbuilder/src/building/builders/parallel_builder/block_building_result_assembler.rs +++ b/crates/rbuilder/src/building/builders/parallel_builder/block_building_result_assembler.rs @@ -8,8 +8,7 @@ use reth::tasks::pool::BlockingTaskPool; use reth_db::Database; use reth_payload_builder::database::CachedReads; use reth_provider::{DatabaseProviderFactory, StateProviderFactory}; -use std::sync::Arc; -use std::{marker::PhantomData, time::Instant}; +use std::{marker::PhantomData, sync::Arc, time::Instant}; use time::OffsetDateTime; use tokio_util::sync::CancellationToken; use tracing::{trace, warn}; diff --git a/crates/rbuilder/src/building/builders/parallel_builder/conflict_resolvers.rs b/crates/rbuilder/src/building/builders/parallel_builder/conflict_resolvers.rs index 046dc61d..6403752d 100644 --- a/crates/rbuilder/src/building/builders/parallel_builder/conflict_resolvers.rs +++ b/crates/rbuilder/src/building/builders/parallel_builder/conflict_resolvers.rs @@ -10,12 +10,15 @@ use std::sync::Arc; use tokio_util::sync::CancellationToken; use tracing::trace; -use super::simulation_cache::{CachedSimulationState, SharedSimulationCache}; -use super::{Algorithm, ConflictTask, ResolutionResult}; - -use crate::building::{BlockBuildingContext, BlockState, PartialBlock}; -use crate::building::{ExecutionError, ExecutionResult}; -use crate::primitives::{OrderId, SimulatedOrder}; +use super::{ + simulation_cache::{CachedSimulationState, SharedSimulationCache}, + Algorithm, ConflictTask, ResolutionResult, +}; + +use crate::{ + building::{BlockBuildingContext, BlockState, ExecutionError, ExecutionResult, PartialBlock}, + primitives::{OrderId, SimulatedOrder}, +}; /// Context for resolving conflicts in merging tasks. #[derive(Debug)] diff --git a/crates/rbuilder/src/building/builders/parallel_builder/conflict_resolving_pool.rs b/crates/rbuilder/src/building/builders/parallel_builder/conflict_resolving_pool.rs index c4b144eb..a6ac2b72 100644 --- a/crates/rbuilder/src/building/builders/parallel_builder/conflict_resolving_pool.rs +++ b/crates/rbuilder/src/building/builders/parallel_builder/conflict_resolving_pool.rs @@ -3,18 +3,17 @@ use crossbeam_queue::SegQueue; use eyre::Result; use rayon::{ThreadPool, ThreadPoolBuilder}; use reth_provider::StateProviderFactory; -use std::sync::mpsc as std_mpsc; -use std::sync::Arc; -use std::time::Instant; +use std::{ + sync::{mpsc as std_mpsc, Arc}, + time::Instant, +}; use tokio_util::sync::CancellationToken; use tracing::{trace, warn}; -use super::conflict_task_generator::get_tasks_for_group; -use super::ConflictResolutionResultPerGroup; -use super::TaskPriority; use super::{ - conflict_resolvers::ResolverContext, simulation_cache::SharedSimulationCache, ConflictGroup, - ConflictTask, GroupId, ResolutionResult, + conflict_resolvers::ResolverContext, conflict_task_generator::get_tasks_for_group, + simulation_cache::SharedSimulationCache, ConflictGroup, ConflictResolutionResultPerGroup, + ConflictTask, GroupId, ResolutionResult, TaskPriority, }; use crate::building::BlockBuildingContext; diff --git a/crates/rbuilder/src/building/builders/parallel_builder/conflict_task_generator.rs b/crates/rbuilder/src/building/builders/parallel_builder/conflict_task_generator.rs index 6d9e7b06..ee1931ae 100644 --- a/crates/rbuilder/src/building/builders/parallel_builder/conflict_task_generator.rs +++ b/crates/rbuilder/src/building/builders/parallel_builder/conflict_task_generator.rs @@ -1,18 +1,15 @@ use crate::primitives::SimulatedOrder; -use ahash::HashMap; -use ahash::HashSet; +use ahash::{HashMap, HashSet}; use alloy_primitives::{utils::format_ether, U256}; use crossbeam_queue::SegQueue; use itertools::Itertools; use std::time::Instant; use tracing::{trace, warn}; -use super::task::ConflictTask; -use super::ConflictGroup; -use super::ConflictResolutionResultPerGroup; -use super::GroupId; -use super::ResolutionResult; -use super::{Algorithm, TaskPriority, TaskQueue}; +use super::{ + task::ConflictTask, Algorithm, ConflictGroup, ConflictResolutionResultPerGroup, GroupId, + ResolutionResult, TaskPriority, TaskQueue, +}; use std::sync::mpsc as std_mpsc; const THRESHOLD_FOR_SIGNIFICANT_CHANGE: u64 = 20; diff --git a/crates/rbuilder/src/building/builders/parallel_builder/mod.rs b/crates/rbuilder/src/building/builders/parallel_builder/mod.rs index 49546496..e70e682c 100644 --- a/crates/rbuilder/src/building/builders/parallel_builder/mod.rs +++ b/crates/rbuilder/src/building/builders/parallel_builder/mod.rs @@ -18,9 +18,11 @@ use itertools::Itertools; use results_aggregator::BestResults; use serde::Deserialize; use simulation_cache::SharedSimulationCache; -use std::sync::mpsc as std_mpsc; -use std::thread; -use std::{sync::Arc, time::Instant}; +use std::{ + sync::{mpsc as std_mpsc, Arc}, + thread, + time::Instant, +}; use task::*; use time::OffsetDateTime; use tokio_util::sync::CancellationToken; diff --git a/crates/rbuilder/src/building/builders/parallel_builder/results_aggregator.rs b/crates/rbuilder/src/building/builders/parallel_builder/results_aggregator.rs index c0d8a0f6..1b1bfec6 100644 --- a/crates/rbuilder/src/building/builders/parallel_builder/results_aggregator.rs +++ b/crates/rbuilder/src/building/builders/parallel_builder/results_aggregator.rs @@ -1,13 +1,13 @@ use super::{ConflictGroup, GroupId, ResolutionResult}; -use alloy_primitives::utils::format_ether; -use alloy_primitives::U256; +use alloy_primitives::{utils::format_ether, U256}; use dashmap::DashMap; -use std::sync::mpsc as std_mpsc; -use std::sync::{ - atomic::{AtomicU64, Ordering}, - Arc, +use std::{ + sync::{ + atomic::{AtomicU64, Ordering}, + mpsc as std_mpsc, Arc, + }, + time::{Duration, Instant}, }; -use std::time::{Duration, Instant}; use tokio_util::sync::CancellationToken; use tracing::trace; diff --git a/crates/rbuilder/src/building/builders/parallel_builder/simulation_cache.rs b/crates/rbuilder/src/building/builders/parallel_builder/simulation_cache.rs index 05a1b2fe..bcdd3f22 100644 --- a/crates/rbuilder/src/building/builders/parallel_builder/simulation_cache.rs +++ b/crates/rbuilder/src/building/builders/parallel_builder/simulation_cache.rs @@ -4,8 +4,10 @@ use alloy_primitives::U256; use parking_lot::RwLock as PLRwLock; use reth_payload_builder::database::CachedReads; use revm::db::BundleState; -use std::sync::atomic::{AtomicUsize, Ordering}; -use std::sync::Arc; +use std::sync::{ + atomic::{AtomicUsize, Ordering}, + Arc, +}; /// An instance of a simulation result that has been cached. #[derive(Debug, Clone)] diff --git a/crates/rbuilder/src/building/built_block_trace.rs b/crates/rbuilder/src/building/built_block_trace.rs index 9309ff7f..d5c9e579 100644 --- a/crates/rbuilder/src/building/built_block_trace.rs +++ b/crates/rbuilder/src/building/built_block_trace.rs @@ -2,8 +2,7 @@ use super::{BundleErr, ExecutionError, ExecutionResult, OrderErr}; use crate::primitives::{Order, OrderId, OrderReplacementKey}; use ahash::{HashMap, HashSet}; use alloy_primitives::{Address, TxHash, U256}; -use std::collections::hash_map; -use std::time::Duration; +use std::{collections::hash_map, time::Duration}; use time::OffsetDateTime; /// Structs for recording data about a built block, such as what bundles were included, and where txs came from. diff --git a/crates/rbuilder/src/building/order_commit.rs b/crates/rbuilder/src/building/order_commit.rs index 1f60627e..f82e5a56 100644 --- a/crates/rbuilder/src/building/order_commit.rs +++ b/crates/rbuilder/src/building/order_commit.rs @@ -478,6 +478,16 @@ impl<'a, 'b, Tracer: SimulationTracer> PartialBlockFork<'a, 'b, Tracer> { success: res.result.is_success(), cumulative_gas_used, logs: res.result.logs().to_vec(), + // Necessary because rbuilder is one crate that requires deps to have all-or-nothing + // features. This can be removed when logic required for op-rbuilder is + // moved into a dedicated crate. + #[cfg(feature = "optimism")] + deposit_nonce: None, + // Necessary because rbuilder is one crate that requires deps to have all-or-nothing + // features. This can be removed when logic required for op-rbuilder is + // moved into a dedicated crate. + #[cfg(feature = "optimism")] + deposit_receipt_version: None, }; Ok(Ok(TransactionOk { diff --git a/crates/rbuilder/src/live_builder/block_output/relay_submit.rs b/crates/rbuilder/src/live_builder/block_output/relay_submit.rs index 2702df80..01e1fda7 100644 --- a/crates/rbuilder/src/live_builder/block_output/relay_submit.rs +++ b/crates/rbuilder/src/live_builder/block_output/relay_submit.rs @@ -20,8 +20,7 @@ use mockall::automock; use reth_chainspec::ChainSpec; use reth_primitives::SealedBlock; use std::sync::{Arc, Mutex}; -use tokio::sync::Notify; -use tokio::time::Instant; +use tokio::{sync::Notify, time::Instant}; use tokio_util::sync::CancellationToken; use tracing::{debug, error, event, info_span, trace, warn, Instrument, Level}; diff --git a/crates/rbuilder/src/live_builder/config.rs b/crates/rbuilder/src/live_builder/config.rs index 4cbbe30d..517940f8 100644 --- a/crates/rbuilder/src/live_builder/config.rs +++ b/crates/rbuilder/src/live_builder/config.rs @@ -363,7 +363,7 @@ impl LiveBuilderConfig for Config { crate::building::builders::ordering_builder::backtest_simulate_block(config, input) } SpecificBuilderConfig::ParallelBuilder(config) => { - parallel_build_backtest(input, config) + parallel_build_backtest::(input, config) } } } diff --git a/crates/rbuilder/src/live_builder/mod.rs b/crates/rbuilder/src/live_builder/mod.rs index c419f0e7..83a3228b 100644 --- a/crates/rbuilder/src/live_builder/mod.rs +++ b/crates/rbuilder/src/live_builder/mod.rs @@ -39,13 +39,38 @@ use tokio::sync::mpsc; use tokio_util::sync::CancellationToken; use tracing::{debug, info, warn}; -/// Time the proposer have to propose a block from the beginning of the slot (https://www.paradigm.xyz/2023/04/mev-boost-ethereum-consensus Slot anatomy) -const SLOT_PROPOSAL_DURATION: std::time::Duration = Duration::from_secs(4); -/// Delta from slot time to get_header dead line. If we can't get the block header before slot_time + BLOCK_HEADER_DEAD_LINE_DELTA we cancel the slot. -/// Careful: It's signed and usually negative since we need de header BEFORE the slot time. -const BLOCK_HEADER_DEAD_LINE_DELTA: time::Duration = time::Duration::milliseconds(-2500); -/// Polling period while trying to get a block header -const GET_BLOCK_HEADER_PERIOD: time::Duration = time::Duration::milliseconds(250); +#[derive(Debug, Clone)] +pub struct TimingsConfig { + /// Time the proposer have to propose a block from the beginning of the + /// slot (https://www.paradigm.xyz/2023/04/mev-boost-ethereum-consensus Slot anatomy) + pub slot_proposal_duration: Duration, + /// Delta from slot time to get_header dead line. If we can't get the block header + /// before slot_time + BLOCK_HEADER_DEAD_LINE_DELTA we cancel the slot. + /// Careful: It's signed and usually negative since we need de header BEFORE the slot time. + pub block_header_deadline_delta: time::Duration, + /// Polling period while trying to get a block header + pub get_block_header_period: time::Duration, +} + +impl TimingsConfig { + /// Classic rbuilder + pub fn ethereum() -> Self { + Self { + slot_proposal_duration: Duration::from_secs(4), + block_header_deadline_delta: time::Duration::milliseconds(-2500), + get_block_header_period: time::Duration::milliseconds(250), + } + } + + /// Configuration for OP-based chains with fast block times + pub fn optimism() -> Self { + Self { + slot_proposal_duration: Duration::from_secs(0), + block_header_deadline_delta: time::Duration::milliseconds(-25), + get_block_header_period: time::Duration::milliseconds(25), + } + } +} /// Trait used to trigger a new block building process in the slot. pub trait SlotSource { @@ -108,6 +133,7 @@ where "Builder coinbase address: {:?}", self.coinbase_signer.address ); + let timings = self.timings(); if let Some(error_storage_path) = self.error_storage_path { spawn_error_storage_writer(error_storage_path, self.global_cancellation.clone()) @@ -170,7 +196,7 @@ where "Received payload, time till slot timestamp", ); - let time_until_slot_end = time_to_slot + SLOT_PROPOSAL_DURATION; + let time_until_slot_end = time_to_slot + timings.slot_proposal_duration; if time_until_slot_end.is_negative() { warn!( slot = payload.slot(), @@ -183,7 +209,8 @@ where // @Nicer let parent_block = payload.parent_block_hash(); let timestamp = payload.timestamp(); - match wait_for_block_header(parent_block, timestamp, &self.provider).await { + match wait_for_block_header(parent_block, timestamp, &self.provider, &timings).await + { Ok(header) => header, Err(err) => { warn!("Failed to get parent header for new slot: {:?}", err); @@ -231,6 +258,17 @@ where } Ok(()) } + + // Currently we only need two timings config, depending on whether rbuilder is being + // used in the optimism context. If further customisation is required in the future + // this should be improved on. + fn timings(&self) -> TimingsConfig { + if cfg!(feature = "optimism") { + TimingsConfig::optimism() + } else { + TimingsConfig::ethereum() + } + } } /// May fail if we wait too much (see [BLOCK_HEADER_DEAD_LINE_DELTA]) @@ -238,18 +276,19 @@ async fn wait_for_block_header

( block: B256, slot_time: OffsetDateTime, provider: P, + timings: &TimingsConfig, ) -> eyre::Result

where P: HeaderProvider, { - let dead_line = slot_time + BLOCK_HEADER_DEAD_LINE_DELTA; - while OffsetDateTime::now_utc() < dead_line { + let deadline = slot_time + timings.block_header_deadline_delta; + while OffsetDateTime::now_utc() < deadline { if let Some(header) = provider.header(&block)? { return Ok(header); } else { let time_to_sleep = min( - dead_line - OffsetDateTime::now_utc(), - GET_BLOCK_HEADER_PERIOD, + deadline - OffsetDateTime::now_utc(), + timings.get_block_header_period, ); if time_to_sleep.is_negative() { break; diff --git a/crates/rbuilder/src/live_builder/order_input/rpc_server.rs b/crates/rbuilder/src/live_builder/order_input/rpc_server.rs index 770dfdbf..5b37cf18 100644 --- a/crates/rbuilder/src/live_builder/order_input/rpc_server.rs +++ b/crates/rbuilder/src/live_builder/order_input/rpc_server.rs @@ -4,8 +4,7 @@ use crate::primitives::{ Bundle, BundleReplacementKey, MempoolTx, Order, }; use alloy_primitives::Address; -use jsonrpsee::types::ErrorObject; -use jsonrpsee::{server::Server, RpcModule}; +use jsonrpsee::{server::Server, types::ErrorObject, RpcModule}; use reth_primitives::Bytes; use serde::Deserialize; use std::{ @@ -54,7 +53,7 @@ pub async fn start_server_accepting_bundles( } }; - let bundle: Bundle = match raw_bundle.decode(TxEncoding::WithBlobData) { + let bundle: Bundle = match raw_bundle.try_into(TxEncoding::WithBlobData) { Ok(bundle) => bundle, Err(err) => { warn!(?err, "Failed to parse bundle"); diff --git a/crates/rbuilder/src/live_builder/payload_events/payload_source.rs b/crates/rbuilder/src/live_builder/payload_events/payload_source.rs index 228c5e6e..01d6328b 100644 --- a/crates/rbuilder/src/live_builder/payload_events/payload_source.rs +++ b/crates/rbuilder/src/live_builder/payload_events/payload_source.rs @@ -75,6 +75,7 @@ impl CLPayloadSource { /// Recreates the PayloadSource if: /// - PayloadSource::recv returns None /// - PayloadSource::recv does not deliver a new PayloadAttributesEvent in some time (recv_timeout) +#[derive(Debug)] pub struct PayloadSourceReconnector { receiver: mpsc::UnboundedReceiver, /// In case we cancel via the CancellationToken this handle allows us to wait for the internal spawned task to end. @@ -151,7 +152,7 @@ impl PayloadSourceReconnector { } } - async fn recv(&mut self) -> Option { + pub async fn recv(&mut self) -> Option { self.receiver.recv().await } } diff --git a/crates/rbuilder/src/live_builder/payload_events/relay_epoch_cache.rs b/crates/rbuilder/src/live_builder/payload_events/relay_epoch_cache.rs index 26e7a56f..05393fae 100644 --- a/crates/rbuilder/src/live_builder/payload_events/relay_epoch_cache.rs +++ b/crates/rbuilder/src/live_builder/payload_events/relay_epoch_cache.rs @@ -10,7 +10,7 @@ use tokio_stream::StreamExt; use tracing::{info_span, trace, warn}; /// Info about a slot obtained from a relay. -#[derive(Debug, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, Clone, Hash, PartialEq, Eq, Default)] pub struct SlotData { /// fee recipient the validator chose. pub fee_recipient: Address, diff --git a/crates/rbuilder/src/mev_boost/error.rs b/crates/rbuilder/src/mev_boost/error.rs index 4517b17a..e3713b87 100644 --- a/crates/rbuilder/src/mev_boost/error.rs +++ b/crates/rbuilder/src/mev_boost/error.rs @@ -13,11 +13,11 @@ pub enum RelayError { RelayError(#[from] RedactableRelayErrorResponse), #[cfg_attr( - not(feature = "redact_sensitive"), + not(feature = "redact-sensitive"), error("Unknown relay response, status: {0}, body: {1}") )] #[cfg_attr( - feature = "redact_sensitive", + feature = "redact-sensitive", error("Unknown relay response, status: {0}, body: [REDACTED]") )] UnknownRelayError(StatusCode, String), @@ -51,12 +51,12 @@ impl From for RedactableReqwestError { } impl Display for RedactableReqwestError { - #[cfg(not(feature = "redact_sensitive"))] + #[cfg(not(feature = "redact-sensitive"))] fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.0) } - #[cfg(feature = "redact_sensitive")] + #[cfg(feature = "redact-sensitive")] fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { if self.0.is_builder() { write!(f, "Redacted Reqwest Error: Builder") @@ -89,7 +89,7 @@ pub struct RedactableRelayErrorResponse { } impl std::fmt::Display for RedactableRelayErrorResponse { - #[cfg(not(feature = "redact_sensitive"))] + #[cfg(not(feature = "redact-sensitive"))] fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, @@ -99,7 +99,7 @@ impl std::fmt::Display for RedactableRelayErrorResponse { ) } - #[cfg(feature = "redact_sensitive")] + #[cfg(feature = "redact-sensitive")] fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, diff --git a/crates/rbuilder/src/mev_boost/mod.rs b/crates/rbuilder/src/mev_boost/mod.rs index e968b442..914d363e 100644 --- a/crates/rbuilder/src/mev_boost/mod.rs +++ b/crates/rbuilder/src/mev_boost/mod.rs @@ -274,11 +274,11 @@ pub enum SubmitBlockErr { /// RPC validates the submissions (eg: limit of txs) much more that our model. RPCConversionError(Error), #[cfg_attr( - not(feature = "redact_sensitive"), + not(feature = "redact-sensitive"), error("RPC serialization failed: {0}") )] #[cfg_attr( - feature = "redact_sensitive", + feature = "redact-sensitive", error("RPC serialization failed: [REDACTED]") )] RPCSerializationError(String), diff --git a/crates/rbuilder/src/primitives/serialize.rs b/crates/rbuilder/src/primitives/serialize.rs index 2c6bff75..8ba77c1b 100644 --- a/crates/rbuilder/src/primitives/serialize.rs +++ b/crates/rbuilder/src/primitives/serialize.rs @@ -71,7 +71,7 @@ pub enum RawBundleConvertError { } impl RawBundle { - pub fn decode(self, encoding: TxEncoding) -> Result { + pub fn try_into(self, encoding: TxEncoding) -> Result { let txs = self .txs .into_iter() @@ -512,7 +512,7 @@ impl RawOrder { match self { RawOrder::Bundle(bundle) => Ok(Order::Bundle( bundle - .decode(encoding) + .try_into(encoding) .map_err(RawOrderConvertError::FailedToDecodeBundle)?, )), RawOrder::Tx(tx) => Ok(Order::Tx( @@ -565,7 +565,7 @@ mod tests { let bundle = bundle_request .clone() - .decode(TxEncoding::WithBlobData) + .try_into(TxEncoding::WithBlobData) .expect("failed to convert bundle request to bundle"); let bundle_roundtrip = RawBundle::encode_no_blobs(bundle.clone()); @@ -629,7 +629,7 @@ mod tests { serde_json::from_str(input).expect("failed to decode bundle"); let bundle = bundle_request - .decode(TxEncoding::WithBlobData) + .try_into(TxEncoding::WithBlobData) .expect("failed to convert bundle request to bundle"); assert_eq!( @@ -654,7 +654,7 @@ mod tests { serde_json::from_str(bundle_json).expect("failed to decode bundle"); let bundle = bundle_request - .decode(TxEncoding::WithBlobData) + .try_into(TxEncoding::WithBlobData) .expect("failed to convert bundle request to bundle"); assert_eq!( diff --git a/crates/rbuilder/src/roothash/prefetcher.rs b/crates/rbuilder/src/roothash/prefetcher.rs index 5190810b..b9b4dab7 100644 --- a/crates/rbuilder/src/roothash/prefetcher.rs +++ b/crates/rbuilder/src/roothash/prefetcher.rs @@ -11,7 +11,10 @@ use reth::providers::providers::ConsistentDbView; use reth_db::database::Database; use reth_errors::ProviderError; use reth_provider::DatabaseProviderFactory; -use tokio::sync::broadcast::{self, error::RecvError, error::TryRecvError}; +use tokio::sync::broadcast::{ + self, + error::{RecvError, TryRecvError}, +}; use tokio_util::sync::CancellationToken; use tracing::{error, trace, warn}; diff --git a/crates/rbuilder/src/utils/mod.rs b/crates/rbuilder/src/utils/mod.rs index 7410ed8d..97af06f9 100644 --- a/crates/rbuilder/src/utils/mod.rs +++ b/crates/rbuilder/src/utils/mod.rs @@ -18,8 +18,10 @@ use alloy_primitives::{Address, Sign, I256, U256}; use alloy_provider::RootProvider; use alloy_transport::BoxTransport; -use crate::primitives::serialize::{RawTx, TxEncoding}; -use crate::primitives::TransactionSignedEcRecoveredWithBlobs; +use crate::primitives::{ + serialize::{RawTx, TxEncoding}, + TransactionSignedEcRecoveredWithBlobs, +}; use alloy_consensus::TxEnvelope; use alloy_eips::eip2718::Encodable2718; pub use noncer::{NonceCache, NonceCacheRef}; diff --git a/crates/rbuilder/src/validation_api_client.rs b/crates/rbuilder/src/validation_api_client.rs index b59fb3de..302363ae 100644 --- a/crates/rbuilder/src/validation_api_client.rs +++ b/crates/rbuilder/src/validation_api_client.rs @@ -41,8 +41,8 @@ pub enum ValidationError { #[error("Validation failed")] ValidationFailed(ErrorPayload), - #[cfg_attr(not(feature = "redact_sensitive"), error("Local usage error: {0}"))] - #[cfg_attr(feature = "redact_sensitive", error("Local usage error: [REDACTED]"))] + #[cfg_attr(not(feature = "redact-sensitive"), error("Local usage error: {0}"))] + #[cfg_attr(feature = "redact-sensitive", error("Local usage error: [REDACTED]"))] LocalUsageError(Box), } diff --git a/crates/transaction-pool-bundle-ext/Cargo.toml b/crates/transaction-pool-bundle-ext/Cargo.toml new file mode 100644 index 00000000..9106b7aa --- /dev/null +++ b/crates/transaction-pool-bundle-ext/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "transaction-pool-bundle-ext" +version.workspace = true +edition.workspace = true + +[dependencies] +reth = { workspace = true } +reth-eth-wire-types = { workspace = true } +reth-primitives = { workspace = true } +reth-rpc-types = { workspace = true } +reth-transaction-pool = { workspace = true } + +tokio = { workspace = true } + diff --git a/crates/transaction-pool-bundle-ext/bundle_pool_ops/rbuilder/Cargo.toml b/crates/transaction-pool-bundle-ext/bundle_pool_ops/rbuilder/Cargo.toml new file mode 100644 index 00000000..ae059f56 --- /dev/null +++ b/crates/transaction-pool-bundle-ext/bundle_pool_ops/rbuilder/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "rbuilder-bundle-pool-operations" +version = "0.1.0" +edition = "2021" + +[dependencies] +transaction-pool-bundle-ext = { path = "../.." } +rbuilder = { path = "../../../rbuilder" } + +reth-primitives = { workspace = true } +reth-provider = { workspace = true } +reth-db-api = { workspace = true } +reth-rpc-types = { workspace = true } + +derive_more = { workspace = true } +eyre = { workspace = true } +tokio = { workspace = true } +tokio-util = { workspace = true } +tracing = { workspace = true } + +[features] +optimism = [ + "reth-primitives/optimism", + "rbuilder/optimism", + "reth-provider/optimism", + "reth-db-api/optimism" +] diff --git a/crates/transaction-pool-bundle-ext/bundle_pool_ops/rbuilder/src/lib.rs b/crates/transaction-pool-bundle-ext/bundle_pool_ops/rbuilder/src/lib.rs new file mode 100644 index 00000000..9a6ce200 --- /dev/null +++ b/crates/transaction-pool-bundle-ext/bundle_pool_ops/rbuilder/src/lib.rs @@ -0,0 +1,280 @@ +//! Implementation of [`BundlePoolOperations`] for the classic rbuilder that +//! supports [`EthSendBundle`]s. + +#![cfg_attr(not(test), warn(unused_crate_dependencies))] + +use core::fmt; +use std::{fmt::Formatter, path::Path, sync::Arc, time::Duration}; + +use derive_more::From; +use rbuilder::{ + building::{ + builders::{ + block_building_helper::BlockBuildingHelper, ordering_builder::OrderingBuilderConfig, + UnfinishedBlockBuildingSink, UnfinishedBlockBuildingSinkFactory, + }, + Sorting, + }, + live_builder::{ + base_config::load_config_toml_and_env, + config::{create_builders, BuilderConfig, Config, SpecificBuilderConfig}, + order_input::{rpc_server::RawCancelBundle, ReplaceableOrderPoolCommand}, + payload_events::MevBoostSlotData, + SlotSource, + }, + primitives::{Bundle, BundleReplacementKey, Order}, +}; +use reth_db_api::Database; +use reth_primitives::{TransactionSigned, U256}; +use reth_provider::{DatabaseProviderFactory, HeaderProvider, StateProviderFactory}; +use reth_rpc_types::beacon::events::PayloadAttributesEvent; +use tokio::{ + sync::{ + mpsc::{self, error::SendError}, + watch, + }, + task, + time::sleep, +}; +use tokio_util::sync::CancellationToken; +use tracing::error; +use transaction_pool_bundle_ext::BundlePoolOperations; + +/// [`BundlePoolOperations`] implementation which uses components of the +/// [`rbuilder`] under the hood to handle classic [`EthSendBundle`]s. +pub struct BundlePoolOps { + // Channel to stream new [`OrderPool`] events to the rbuilder + orderpool_tx: mpsc::Sender, + // Channel to stream new payload attribute events to rbuilder + payload_attributes_tx: mpsc::UnboundedSender<(PayloadAttributesEvent, Option)>, + /// Channel containing the latest [`BlockBuildingHelper`] recieved from the rbuilder + block_building_helper_rx: watch::Receiver>>, +} + +#[derive(Debug)] +struct OurSlotSource { + /// Channel [`OurSlotSource`] uses to receive payload attributes from reth + payload_attributes_rx: mpsc::UnboundedReceiver<(PayloadAttributesEvent, Option)>, +} + +impl SlotSource for OurSlotSource { + fn recv_slot_channel(self) -> mpsc::UnboundedReceiver { + let (slot_sender, slot_receiver) = mpsc::unbounded_channel(); + + // Spawn a task that receives payload attributes, converts them + // into [`MevBoostSlotData`] for rbuilder, then forwards them. + tokio::spawn(async move { + let mut recv = self.payload_attributes_rx; + while let Some((payload_event, gas_limit)) = recv.recv().await { + let mev_boost_data = MevBoostSlotData { + payload_attributes_event: payload_event, + suggested_gas_limit: gas_limit.unwrap_or(0), + relays: vec![], + slot_data: Default::default(), + }; + + if slot_sender.send(mev_boost_data).is_err() { + error!("Error sending MevBoostSlotData through channel"); + break; + } + } + }); + + // Return the receiver end for SlotSource trait + slot_receiver + } +} + +impl BundlePoolOps { + pub async fn new( + provider: P, + rbuilder_config_path: impl AsRef, + ) -> Result + where + DB: Database + Clone + 'static, + P: DatabaseProviderFactory + StateProviderFactory + HeaderProvider + Clone + 'static, + { + // Create the payload source to trigger new block building + let cancellation_token = CancellationToken::new(); + let (payload_attributes_tx, payload_attributes_rx) = mpsc::unbounded_channel(); + let slot_source = OurSlotSource { + payload_attributes_rx, + }; + + let (block_building_helper_tx, block_building_helper_rx) = watch::channel(None); + let sink_factory = SinkFactory { + block_building_helper_tx, + }; + + // Spawn the builder! + let config: Config = load_config_toml_and_env(rbuilder_config_path)?; + + let builder_strategy = BuilderConfig { + name: "mp-ordering".to_string(), + builder: SpecificBuilderConfig::OrderingBuilder(OrderingBuilderConfig { + discard_txs: true, + sorting: Sorting::MaxProfit, + failed_order_retries: 1, + drop_failed_orders: true, + coinbase_payment: false, + build_duration_deadline_ms: None, + }), + }; + + let builders = create_builders( + vec![builder_strategy], + config.base_config.live_root_hash_config().unwrap(), + config.base_config.root_hash_task_pool().unwrap(), + config.base_config.sbundle_mergeabe_signers(), + ); + + // Build and run the process + let builder = config + .base_config + .create_builder_with_provider_factory::( + cancellation_token, + Box::new(sink_factory), + slot_source, + provider, + ) + .await + .unwrap() + .with_builders(builders); + let orderpool_tx = builder.orderpool_sender.clone(); + + // Spawn in separate thread + let _handle = task::spawn(async move { + // Wait for 5 seconds for reth to init + sleep(Duration::from_secs(5)).await; + + builder.run().await.unwrap(); + + Ok::<(), ()> + }); + + Ok(BundlePoolOps { + block_building_helper_rx, + payload_attributes_tx, + orderpool_tx, + }) + } +} + +impl BundlePoolOperations for BundlePoolOps { + /// Signed eth transaction + type Transaction = TransactionSigned; + type Bundle = Bundle; + type CancelBundleReq = RawCancelBundle; + type Error = Error; + + async fn add_bundle(&self, bundle: Self::Bundle) -> Result<(), Self::Error> { + self.orderpool_tx + .send(ReplaceableOrderPoolCommand::Order(Order::Bundle(bundle))) + .await?; + Ok(()) + } + + async fn cancel_bundle( + &self, + cancel_bundle_request: Self::CancelBundleReq, + ) -> Result<(), Self::Error> { + let key = BundleReplacementKey::new( + cancel_bundle_request.replacement_uuid, + cancel_bundle_request.signing_address, + ); + self.orderpool_tx + .send(ReplaceableOrderPoolCommand::CancelBundle(key)) + .await?; + Ok(()) + } + + fn get_transactions( + &self, + requested_slot: U256, + ) -> Result, Self::Error> { + match *self.block_building_helper_rx.borrow() { + Some(ref block_builder) => { + let rbuilder_slot = block_builder.building_context().block_env.number; + if rbuilder_slot != requested_slot { + return Ok(vec![]); + } + let orders = block_builder.built_block_trace().included_orders.clone(); + let orders = orders + .iter() + .flat_map(|order| order.txs.iter()) + .map(|er| er.clone().into_internal_tx_unsecure().into_signed()) + .collect::>(); + Ok(orders) + } + None => Ok(vec![]), + } + } + + fn notify_payload_attributes_event( + &self, + payload_attributes: PayloadAttributesEvent, + gas_limit: Option, + ) -> Result<(), Self::Error> { + self.payload_attributes_tx + .send((payload_attributes, gas_limit))?; + Ok(()) + } +} + +struct Sink { + /// Channel for rbuilder to notify us of new [`BlockBuildingHelper`]s as it builds blocks + block_building_helper_tx: watch::Sender>>, +} + +impl derive_more::Debug for Sink { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("Sink").finish() + } +} + +struct SinkFactory { + /// Channel for rbuilder to notify us of new [`BlockBuildingHelper`]s as it builds blocks + block_building_helper_tx: watch::Sender>>, +} + +impl derive_more::Debug for SinkFactory { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("SinkFactory").finish() + } +} + +impl UnfinishedBlockBuildingSinkFactory for SinkFactory { + fn create_sink( + &mut self, + _slot_data: MevBoostSlotData, + _cancel: CancellationToken, + ) -> Arc { + Arc::new(Sink { + block_building_helper_tx: self.block_building_helper_tx.clone(), + }) + } +} + +impl UnfinishedBlockBuildingSink for Sink { + fn new_block(&self, block: Box) { + self.block_building_helper_tx.send(Some(block)).unwrap() + } + + fn can_use_suggested_fee_recipient_as_coinbase(&self) -> bool { + true + } +} + +#[allow(clippy::large_enum_variant)] +/// [`BundlePoolOperations`] error type. +#[derive(Debug, From)] +pub enum Error { + #[from] + Eyre(eyre::Error), + + #[from] + SendPayloadAttributes(SendError<(PayloadAttributesEvent, Option)>), + + #[from] + SendReplaceableOrderPoolCommand(SendError), +} diff --git a/crates/transaction-pool-bundle-ext/src/bundle_supported_pool.rs b/crates/transaction-pool-bundle-ext/src/bundle_supported_pool.rs new file mode 100644 index 00000000..59efcd4f --- /dev/null +++ b/crates/transaction-pool-bundle-ext/src/bundle_supported_pool.rs @@ -0,0 +1,410 @@ +//! Houses [`BundleSupportedPool`]. + +use reth::providers::ChangedAccount; +use reth_eth_wire_types::HandleMempoolData; +use reth_primitives::{Address, PooledTransactionsElement, TxHash, U256}; +use reth_rpc_types::{beacon::events::PayloadAttributesEvent, BlobTransactionSidecar}; +use reth_transaction_pool::{ + AllPoolTransactions, AllTransactionsEvents, BestTransactions, BestTransactionsAttributes, + BlobStore, BlobStoreError, BlockInfo, CanonicalStateUpdate, GetPooledTransactionLimit, + NewBlobSidecar, NewTransactionEvent, Pool, PoolConfig, PoolResult, PoolSize, + PropagatedTransactions, TransactionEvents, TransactionListenerKind, TransactionOrdering, + TransactionOrigin, TransactionPool, TransactionPoolExt as TransactionPoolBlockInfoExt, + TransactionValidator, ValidPoolTransaction, +}; +use std::{collections::HashSet, future::Future, sync::Arc}; +use tokio::sync::mpsc::Receiver; + +use crate::{traits::BundlePoolOperations, TransactionPoolBundleExt}; + +/// Allows easily creating a `Pool` type for reth's `PoolBuilder` that supports +/// a new [`BundlePool`] running alongside [`Pool`]. +/// +/// To be used in place of the reth [`Pool`] when defining the `Pool` type +/// for reth's `PoolBuilder`. +/// +/// Just as logic for the [`Pool`] is generic based on `V`, `T`, `S` generics, bundle pool +/// logic is generic based on a new `B` generic that implements [`BundlePoolOperations`]. +/// +/// Achieves this by implementing [`TransactionPool`] and [`BundlePoolOperations`], +/// and therefore also [`TransactionPoolBundleExt`]. +/// +/// ## Example +/// +/// ```ignore +/// /// An extended optimism transaction pool with bundle support. +/// #[derive(Debug, Default, Clone, Copy)] +/// pub struct CustomPoolBuilder; +/// +/// pub type MyCustomTransactionPoolWithBundleSupport = BundleSupportedPool< +/// TransactionValidationTaskExecutor>, +/// CoinbaseTipOrdering, +/// S, +/// MyBundlePoolOperationsImplementation, +/// >; +/// +/// impl PoolBuilder for CustomPoolBuilder +/// where +/// Node: FullNodeTypes, +/// { +/// type Pool = MyCustomTransactionPoolWithBundleSupport; +/// // the rest of the PoolBuilder implementation... +/// ``` +#[derive(Debug)] +pub struct BundleSupportedPool { + /// Arc'ed instance of [`Pool`] internals + tx_pool: Arc>, + /// Arc'ed instance of the [`BundlePool`] internals + bundle_pool: Arc>, +} + +impl BundleSupportedPool +where + V: TransactionValidator, + T: TransactionOrdering::Transaction>, + S: BlobStore, + B: BundlePoolOperations, +{ + pub fn new( + validator: V, + ordering: T, + blob_store: S, + bundle_ops: B, + tx_pool_config: PoolConfig, + ) -> Self { + Self { + tx_pool: Arc::new(Pool::::new( + validator, + ordering, + blob_store, + tx_pool_config, + )), + bundle_pool: Arc::new(BundlePool::::new(bundle_ops)), + } + } +} + +/// Houses generic bundle logic. +#[derive(Debug, Default)] +struct BundlePool { + pub ops: B, +} + +impl BundlePool { + fn new(ops: B) -> Self { + Self { ops } + } +} + +/// [`TransactionPool`] requires implementors to be [`Clone`]. +impl Clone for BundleSupportedPool { + fn clone(&self) -> Self { + Self { + tx_pool: Arc::clone(&self.tx_pool), + bundle_pool: Arc::clone(&self.bundle_pool), + } + } +} + +/// Implements the [`TransactionPool`] interface by delegating to the inner `tx_pool`. +/// TODO: Use a crate like `delegate!` or `ambassador` to automate this. +impl TransactionPool for BundleSupportedPool +where + V: TransactionValidator, + T: TransactionOrdering::Transaction>, + S: BlobStore, + B: BundlePoolOperations, +{ + type Transaction = T::Transaction; + + fn pool_size(&self) -> PoolSize { + self.tx_pool.pool_size() + } + + fn block_info(&self) -> BlockInfo { + self.tx_pool.block_info() + } + + async fn add_transaction_and_subscribe( + &self, + origin: TransactionOrigin, + transaction: Self::Transaction, + ) -> PoolResult { + self.tx_pool + .add_transaction_and_subscribe(origin, transaction) + .await + } + + async fn add_transaction( + &self, + origin: TransactionOrigin, + transaction: Self::Transaction, + ) -> PoolResult { + self.tx_pool.add_transaction(origin, transaction).await + } + + async fn add_transactions( + &self, + origin: TransactionOrigin, + transactions: Vec, + ) -> Vec> { + self.tx_pool.add_transactions(origin, transactions).await + } + + fn transaction_event_listener(&self, tx_hash: TxHash) -> Option { + self.tx_pool.transaction_event_listener(tx_hash) + } + + fn all_transactions_event_listener(&self) -> AllTransactionsEvents { + self.tx_pool.all_transactions_event_listener() + } + + fn pending_transactions_listener_for(&self, kind: TransactionListenerKind) -> Receiver { + self.tx_pool.pending_transactions_listener_for(kind) + } + + fn blob_transaction_sidecars_listener(&self) -> Receiver { + self.tx_pool.blob_transaction_sidecars_listener() + } + + fn get_pending_transactions_by_origin( + &self, + origin: TransactionOrigin, + ) -> Vec>> { + self.tx_pool.get_pending_transactions_by_origin(origin) + } + + fn new_transactions_listener_for( + &self, + kind: TransactionListenerKind, + ) -> Receiver> { + self.tx_pool.new_transactions_listener_for(kind) + } + + fn pooled_transaction_hashes(&self) -> Vec { + self.tx_pool.pooled_transaction_hashes() + } + + fn pooled_transaction_hashes_max(&self, max: usize) -> Vec { + self.tx_pool.pooled_transaction_hashes_max(max) + } + + fn pooled_transactions(&self) -> Vec>> { + self.tx_pool.pooled_transactions() + } + + fn pooled_transactions_max( + &self, + max: usize, + ) -> Vec>> { + self.tx_pool.pooled_transactions_max(max) + } + + fn get_pooled_transaction_elements( + &self, + tx_hashes: Vec, + limit: GetPooledTransactionLimit, + ) -> Vec { + self.tx_pool + .get_pooled_transaction_elements(tx_hashes, limit) + } + + fn get_pooled_transaction_element(&self, tx_hash: TxHash) -> Option { + self.tx_pool.get_pooled_transaction_element(tx_hash) + } + + fn best_transactions( + &self, + ) -> Box>>> { + self.tx_pool.best_transactions() + } + + #[allow(deprecated)] + fn best_transactions_with_base_fee( + &self, + base_fee: u64, + ) -> Box>>> { + self.tx_pool.best_transactions_with_base_fee(base_fee) + } + + fn best_transactions_with_attributes( + &self, + best_transactions_attributes: BestTransactionsAttributes, + ) -> Box>>> { + self.tx_pool + .best_transactions_with_attributes(best_transactions_attributes) + } + + fn pending_transactions(&self) -> Vec>> { + self.tx_pool.pending_transactions() + } + + fn queued_transactions(&self) -> Vec>> { + self.tx_pool.queued_transactions() + } + + fn all_transactions(&self) -> AllPoolTransactions { + self.tx_pool.all_transactions() + } + + fn remove_transactions( + &self, + hashes: Vec, + ) -> Vec>> { + self.tx_pool.remove_transactions(hashes) + } + + fn retain_unknown(&self, announcement: &mut A) + where + A: HandleMempoolData, + { + self.tx_pool.retain_unknown(announcement) + } + + fn get(&self, tx_hash: &TxHash) -> Option>> { + self.tx_pool.get(tx_hash) + } + + fn get_all(&self, txs: Vec) -> Vec>> { + self.tx_pool.get_all(txs) + } + + fn on_propagated(&self, txs: PropagatedTransactions) { + self.tx_pool.on_propagated(txs) + } + + fn get_transactions_by_sender( + &self, + sender: Address, + ) -> Vec>> { + self.tx_pool.get_transactions_by_sender(sender) + } + + fn get_transaction_by_sender_and_nonce( + &self, + sender: Address, + nonce: u64, + ) -> Option>> { + self.tx_pool + .get_transaction_by_sender_and_nonce(sender, nonce) + } + + fn get_transactions_by_origin( + &self, + origin: TransactionOrigin, + ) -> Vec>> { + self.tx_pool.get_transactions_by_origin(origin) + } + + fn unique_senders(&self) -> HashSet
{ + self.tx_pool.unique_senders() + } + + fn get_blob(&self, tx_hash: TxHash) -> Result, BlobStoreError> { + self.tx_pool.get_blob(tx_hash) + } + + fn get_all_blobs( + &self, + tx_hashes: Vec, + ) -> Result, BlobStoreError> { + self.tx_pool.get_all_blobs(tx_hashes) + } + + fn get_all_blobs_exact( + &self, + tx_hashes: Vec, + ) -> Result, BlobStoreError> { + self.tx_pool.get_all_blobs_exact(tx_hashes) + } +} + +/// Implements the [`BundlePoolOperations`] interface by delegating to the inner `bundle_pool`. +/// TODO: Use a crate like `delegate!` or `ambassador` to automate this. +impl BundlePoolOperations for BundleSupportedPool +where + V: TransactionValidator, + T: TransactionOrdering::Transaction>, + S: BlobStore, + B: BundlePoolOperations, +{ + type Bundle = ::Bundle; + type CancelBundleReq = ::CancelBundleReq; + type Transaction = ::Transaction; + type Error = ::Error; + + fn add_bundle( + &self, + bundle: Self::Bundle, + ) -> impl Future> + Send { + self.bundle_pool.ops.add_bundle(bundle) + } + + fn cancel_bundle( + &self, + cancel_bundle_req: Self::CancelBundleReq, + ) -> impl Future> + Send { + self.bundle_pool.ops.cancel_bundle(cancel_bundle_req) + } + + fn get_transactions( + &self, + slot: U256, + ) -> Result, Self::Error> { + self.bundle_pool.ops.get_transactions(slot) + } + + fn notify_payload_attributes_event( + &self, + payload_attributes: PayloadAttributesEvent, + gas_limit: Option, + ) -> Result<(), Self::Error> { + self.bundle_pool + .ops + .notify_payload_attributes_event(payload_attributes, gas_limit) + } +} + +// Finally, now that [`BundleSupportedPool`] has both [`TransactionPool`] and +// [`BundlePoolOperations`] implemented, it can implement [`TransactionPoolBundleExt`]. +impl TransactionPoolBundleExt for BundleSupportedPool +where + V: TransactionValidator, + T: TransactionOrdering::Transaction>, + S: BlobStore, + B: BundlePoolOperations, +{ +} + +/// [`TransactionPool`] often requires implementing the block info extension. +impl TransactionPoolBlockInfoExt for BundleSupportedPool +where + V: TransactionValidator, + T: TransactionOrdering::Transaction>, + S: BlobStore, + B: BundlePoolOperations, +{ + fn set_block_info(&self, info: BlockInfo) { + self.tx_pool.set_block_info(info) + } + + fn on_canonical_state_change(&self, update: CanonicalStateUpdate<'_>) { + self.tx_pool.on_canonical_state_change(update); + } + + fn update_accounts(&self, accounts: Vec) { + self.tx_pool.update_accounts(accounts); + } + + fn delete_blob(&self, tx: TxHash) { + self.tx_pool.delete_blob(tx) + } + + fn delete_blobs(&self, txs: Vec) { + self.tx_pool.delete_blobs(txs) + } + + fn cleanup_blobs(&self) { + self.tx_pool.cleanup_blobs() + } +} diff --git a/crates/transaction-pool-bundle-ext/src/lib.rs b/crates/transaction-pool-bundle-ext/src/lib.rs new file mode 100644 index 00000000..57ff22c1 --- /dev/null +++ b/crates/transaction-pool-bundle-ext/src/lib.rs @@ -0,0 +1,28 @@ +//! Crate facilitating simple extension of the reth `TransationPool` with +//! arbitrary bundle support. +//! +//! Contains +//! - A reth `TransactionPool` trait extension ([`TransactionPoolBundleExt`]) +//! allowing bundle support to be added into reth nodes. +//! +//! - A [`TransactionPoolBundleExt`] implementation [`BundleSupportedPool`], +//! which encapsulates the reth `TransactionPool` and a generic implementation +//! of the [`BundlePoolOperations`] trait. +//! +//! ## Usage +//! +//! 1. When implementing `PoolBuilder` on your node, pass a custom `type Pool ...` +//! that is a [`BundleSupportedPool`] type. Your [`BundleSupportedPool`] type +//! must specify your chosen [`BundlePoolOperations`] implementation, which you +//! can initialise inside `fn build_pool` when you build the pool. +//! 2. Whereever you require access to bundles, e.g. when implementing RPCs or +//! `PayloadServiceBuilder` on your node, modify the `Pool` trait bound +//! replacing `TransactionPool` with [`TransactionPoolBundleExt`]. This allows access to +//! [`BundlePoolOperations`] methods almost everywhere in the node. + +#![cfg_attr(not(test), warn(unused_crate_dependencies))] + +mod bundle_supported_pool; +mod traits; +pub use bundle_supported_pool::BundleSupportedPool; +pub use traits::{BundlePoolOperations, TransactionPoolBundleExt}; diff --git a/crates/transaction-pool-bundle-ext/src/traits.rs b/crates/transaction-pool-bundle-ext/src/traits.rs new file mode 100644 index 00000000..1d21d0b4 --- /dev/null +++ b/crates/transaction-pool-bundle-ext/src/traits.rs @@ -0,0 +1,51 @@ +//! [`TransactionPoolBundleExt`] implementation generic over any bundle and network type. + +use reth_primitives::U256; +use reth_rpc_types::beacon::events::PayloadAttributesEvent; +use reth_transaction_pool::TransactionPool; +use std::{fmt::Debug, future::Future}; + +/// Bundle-related operations. +/// +/// This API is under active development. +pub trait BundlePoolOperations: Sync + Send { + /// Bundle type + type Bundle: Send; + + /// Cancel bundle request type + type CancelBundleReq; + + /// Error type + type Error: Debug; + + /// Transactions type + type Transaction: Debug; + + /// Add a bundle to the pool, returning an Error if invalid. + fn add_bundle( + &self, + bundle: Self::Bundle, + ) -> impl Future> + Send; + + /// Make a best-effort attempt to cancel a bundle + fn cancel_bundle( + &self, + hash: Self::CancelBundleReq, + ) -> impl Future> + Send; + + /// Get transactions to be included in the head of the next block + fn get_transactions( + &self, + slot: U256, + ) -> Result, Self::Error>; + + /// Notify new payload attributes to use + fn notify_payload_attributes_event( + &self, + payload_attributes: PayloadAttributesEvent, + gas_limit: Option, + ) -> Result<(), Self::Error>; +} + +/// Extension for [TransactionPool] trait adding support for [BundlePoolOperations]. +pub trait TransactionPoolBundleExt: TransactionPool + BundlePoolOperations {} diff --git a/docs/LOGS_PRIVACY.md b/docs/LOGS_PRIVACY.md index 2f27b84d..ab349fdf 100644 --- a/docs/LOGS_PRIVACY.md +++ b/docs/LOGS_PRIVACY.md @@ -6,8 +6,8 @@ Log privacy in rbuilder refers to the level of data exposed in logs via macros l ### Why is this important? -- A non-landed order, if logged in full, could potentially be executed in a later block, causing losses for the order owner. -- Even if an order has built-in protections against unexpected executions, the order owner might still incur gas fees. +- A non-landed order, if logged in full, could potentially be executed in a later block, causing losses for the order owner. +- Even if an order has built-in protections against unexpected executions, the order owner might still incur gas fees. ## External Error Redaction @@ -15,7 +15,7 @@ While we don't log full orders ourselves, we sometimes interact with external sy ### Enabling Error Redaction -To enable external error redaction, use the `redact_sensitive` feature flag. +To enable external error redaction, use the `redact-sensitive` feature flag. ### Example of Error Redaction @@ -30,11 +30,11 @@ pub enum SomeError { RequestError(#[from] RedactableReqwestError), #[cfg_attr( - not(feature = "redact_sensitive"), + not(feature = "redact-sensitive"), error("Unknown relay response, status: {0}, body: {1}") )] #[cfg_attr( - feature = "redact_sensitive", + feature = "redact-sensitive", error("Unknown relay response, status: {0}, body: [REDACTED]") )] UnknownRelayError(StatusCode, String), @@ -57,12 +57,12 @@ impl Debug for RelayError { pub struct RedactableReqwestError(reqwest::Error); impl Display for RedactableReqwestError { - #[cfg(not(feature = "redact_sensitive"))] + #[cfg(not(feature = "redact-sensitive"))] fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.0) } - #[cfg(feature = "redact_sensitive")] + #[cfg(feature = "redact-sensitive")] fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { if self.0.is_builder() { write!(f, "Redacted Reqwest Error: Builder") diff --git a/zepter.yaml b/zepter.yaml new file mode 100644 index 00000000..5ae4ad13 --- /dev/null +++ b/zepter.yaml @@ -0,0 +1,39 @@ +version: + format: 1 + # Minimum zepter version that is expected to work. This is just for printing a nice error + # message when someone tries to use an older version. + binary: 0.13.2 + +# The examples in the following comments assume crate `A` to have a dependency on crate `B`. +workflows: + check: + - [ + "lint", + # Check that `A` activates the features of `B`. + "propagate-feature", + # These are the features to check: + "--features=std,optimism,dev,asm-keccak,jemalloc,jemalloc-prof,tracy-allocator,serde-bincode-compat,serde,test-utils,arbitrary,bench,redact-sensitive", + # Do not try to add a new section into `[features]` of `A` only because `B` expose that feature. There are edge-cases where this is still needed, but we can add them manually. + "--left-side-feature-missing=ignore", + # Ignore the case that `A` it outside of the workspace. Otherwise it will report errors in external dependencies that we have no influence on. + "--left-side-outside-workspace=ignore", + # Auxillary flags: + "--offline", + "--locked", + "--show-path", + "--quiet", + ] + default: + # Running `zepter` with no subcommand will check & fix. + - [$check.0, "--fix"] + +# Will be displayed when any workflow fails: +help: + text: | + rbuilder uses the Zepter CLI to detect abnormalities in Cargo features, e.g. missing propagation. + + It looks like one more more checks failed; please check the console output. + + You can try to automatically address them by installing zepter (`cargo install zepter --locked`) and simply running `zepter` in the workspace root. + links: + - "https://github.com/ggwpez/zepter" From 6d9b7231981b139bcb3f4e422de437c34f2ca6e9 Mon Sep 17 00:00:00 2001 From: Ryan Schneider Date: Thu, 21 Nov 2024 10:59:57 -0800 Subject: [PATCH 02/30] chore(Dockerfile): add --package=${RBUILDER_BIN} to fix reth-rbuilder container (#250) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 📝 Summary The addition of `default-members = ["crates/rbuilder"]` in #244 broke the ability to use `docker build --build-arg RBUILDER_BIN=reth-rbuilder` to build a `reth-rbuilder` container, this should re-enable it. ## 💡 Motivation and Context We're using the `reth-rbuilder` container in kurtosis for Pectra testing. --- ## ✅ I have completed the following steps: * [ ] Run `make lint` * [ ] Run `make test` * [ ] Added tests (if applicable) --------- Co-authored-by: liamaharon --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index bfed71ba..bccd818e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -57,7 +57,7 @@ COPY ./crates/ ./crates/ RUN --mount=type=cache,target=/usr/local/cargo/registry \ --mount=type=cache,target=/usr/local/cargo/git \ --mount=type=cache,target=$SCCACHE_DIR,sharing=locked \ - cargo build --release --features="$FEATURES" --bin=${RBUILDER_BIN} + cargo build --release --features="$FEATURES" --package=${RBUILDER_BIN} # # Runtime container From b557f011220ef50c5c3d576f1ff437f735924d92 Mon Sep 17 00:00:00 2001 From: liamaharon Date: Mon, 25 Nov 2024 11:00:07 +0400 Subject: [PATCH 03/30] op-rbuilder telemetry (#252) Spin up telemetry servers for rbuilder when run in `op-rbuilder`. --- config-optimism-local.toml | 4 ++-- .../bundle_pool_ops/rbuilder/src/lib.rs | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/config-optimism-local.toml b/config-optimism-local.toml index c7ce4b17..b62491d1 100644 --- a/config-optimism-local.toml +++ b/config-optimism-local.toml @@ -1,8 +1,8 @@ log_json = false log_level = "info,rbuilder=debug" -redacted_telemetry_server_port = 6061 +redacted_telemetry_server_port = 6071 redacted_telemetry_server_ip = "0.0.0.0" -full_telemetry_server_port = 6060 +full_telemetry_server_port = 6070 full_telemetry_server_ip = "0.0.0.0" chain = "$HOME/grimoire/optimism/.devnet/genesis-l2.json" diff --git a/crates/transaction-pool-bundle-ext/bundle_pool_ops/rbuilder/src/lib.rs b/crates/transaction-pool-bundle-ext/bundle_pool_ops/rbuilder/src/lib.rs index 9a6ce200..cbca555f 100644 --- a/crates/transaction-pool-bundle-ext/bundle_pool_ops/rbuilder/src/lib.rs +++ b/crates/transaction-pool-bundle-ext/bundle_pool_ops/rbuilder/src/lib.rs @@ -7,6 +7,7 @@ use core::fmt; use std::{fmt::Formatter, path::Path, sync::Arc, time::Duration}; use derive_more::From; +use rbuilder::live_builder::cli::LiveBuilderConfig; use rbuilder::{ building::{ builders::{ @@ -23,6 +24,7 @@ use rbuilder::{ SlotSource, }, primitives::{Bundle, BundleReplacementKey, Order}, + telemetry, }; use reth_db_api::Database; use reth_primitives::{TransactionSigned, U256}; @@ -147,6 +149,22 @@ impl BundlePoolOps { // Wait for 5 seconds for reth to init sleep(Duration::from_secs(5)).await; + // Spawn redacted server that is safe for tdx builders to expose + telemetry::servers::redacted::spawn( + config.base_config().redacted_telemetry_server_address(), + ) + .await + .expect("Failed to start redacted telemetry server"); + + // Spawn debug server that exposes detailed operational information + telemetry::servers::full::spawn( + config.base_config().full_telemetry_server_address(), + config.version_for_telemetry(), + config.base_config().log_enable_dynamic, + ) + .await + .expect("Failed to start full telemetry server"); + builder.run().await.unwrap(); Ok::<(), ()> From 77c73bffb68cbd92dc2bac655f8961dcedc0c300 Mon Sep 17 00:00:00 2001 From: liamaharon Date: Mon, 25 Nov 2024 11:00:20 +0400 Subject: [PATCH 04/30] Add `reth-rbuilder` crate to default-members (#251) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 227e1f68..a9474db6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ members = [ "crates/transaction-pool-bundle-ext/bundle_pool_ops/rbuilder", "crates/eth-sparse-mpt" ] -default-members = ["crates/rbuilder"] +default-members = ["crates/rbuilder", "crates/reth-rbuilder"] resolver = "2" # Like release, but with full debug symbols. Useful for e.g. `perf`. From 4d273c9b52ec6c03ccd2f57bc75d7a9bd32671fc Mon Sep 17 00:00:00 2001 From: ZanCorDX <126988525+ZanCorDX@users.noreply.github.com> Date: Thu, 28 Nov 2024 18:05:28 -0300 Subject: [PATCH 05/30] Reth v1.1.1 (#255) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 📝 Summary - Dependency hell. - In lots of generics (eg:ProviderFactory) the need of DB+Spec was replaced for NodeTypesWithDB. - DatabaseProviderFactory DB now is asociated type and have 2 more. In lots of places now we need Provider: BlockReader. - Lots of types moved to alloy_primitives. - encode/decode_enveloped now are XXX_2718 with minimal changes. - New alloy TrieNode::EmptyRoot . - CachedReads moved to reth::revm::cached. - AsyncStateRoot replaced by ParallelStateRoot (https://github.com/paradigmxyz/reth/pull/11213). - Some HashMap/Set changed to custom versions (eg: alloy_primitives::map::HashMap). - TransactionPool needs stronger restrictions on Transaction. - Updated block finalization (pectra). - Pectra relay submition. ## 💡 Motivation and Context - We needed this for Pectra and to be up to date with reth. - My life was going so well that I needed something to balance it so I did this boring PR. ## ✅ I have completed the following steps: * [X] Run `make lint` * [X] Run `make test` * [ ] Added tests (if applicable) --------- Co-authored-by: Liam Aharon --- .github/workflows/checks.yaml | 7 +- Cargo.lock | 4495 ++++++++++------- Cargo.toml | 153 +- .../benches/trie_insert_bench.rs | 17 +- .../benches/trie_nodes_benches.rs | 6 +- .../src/reth_sparse_trie/hash.rs | 6 +- .../src/reth_sparse_trie/mod.rs | 27 +- .../src/reth_sparse_trie/shared_cache.rs | 10 +- .../src/reth_sparse_trie/trie_fetcher/mod.rs | 40 +- .../src/sparse_mpt/diff_trie/mod.rs | 20 +- .../src/sparse_mpt/diff_trie/tests.rs | 11 +- .../src/sparse_mpt/fixed_trie.rs | 19 +- crates/eth-sparse-mpt/src/utils.rs | 17 +- crates/op-rbuilder/Cargo.toml | 22 +- crates/op-rbuilder/node/Cargo.toml | 19 +- crates/op-rbuilder/node/src/args.rs | 21 +- crates/op-rbuilder/node/src/node.rs | 185 +- crates/op-rbuilder/payload_builder/Cargo.toml | 27 +- .../payload_builder/src/builder.rs | 383 +- crates/op-rbuilder/src/main.rs | 85 +- crates/rbuilder/Cargo.toml | 7 +- .../rbuilder/benches/benchmarks/mev_boost.rs | 29 +- crates/rbuilder/benches/blob_data/blob1.json | 1 + crates/rbuilder/benches/blob_data/blob1.txt | 1 - crates/rbuilder/src/backtest/execute.rs | 10 +- .../src/backtest/fetch/flashbots_db.rs | 3 +- crates/rbuilder/src/backtest/fetch/mod.rs | 2 +- .../src/backtest/redistribute/cli/mod.rs | 8 +- .../rbuilder/src/backtest/redistribute/mod.rs | 32 +- .../resim_landed_block.rs | 4 +- crates/rbuilder/src/backtest/store.rs | 5 +- crates/rbuilder/src/beacon_api_client/mod.rs | 2 +- .../rbuilder/src/bin/debug-bench-machine.rs | 4 +- crates/rbuilder/src/bin/dummy-builder.rs | 27 +- .../rbuilder/src/building/block_orders/mod.rs | 2 +- .../block_orders/multi_share_bundle_merger.rs | 4 +- .../src/building/block_orders/test_context.rs | 2 +- .../builders/block_building_helper.rs | 30 +- .../builders/mock_block_building_helper.rs | 3 +- crates/rbuilder/src/building/builders/mod.rs | 10 +- .../src/building/builders/ordering_builder.rs | 35 +- .../block_building_result_assembler.rs | 15 +- .../parallel_builder/conflict_resolvers.rs | 11 +- .../conflict_task_generator.rs | 8 +- .../builders/parallel_builder/groups.rs | 5 +- .../building/builders/parallel_builder/mod.rs | 31 +- .../parallel_builder/simulation_cache.rs | 9 +- crates/rbuilder/src/building/conflict.rs | 3 +- crates/rbuilder/src/building/evm_inspector.rs | 7 +- crates/rbuilder/src/building/mod.rs | 191 +- crates/rbuilder/src/building/order_commit.rs | 23 +- crates/rbuilder/src/building/payout_tx.rs | 10 +- crates/rbuilder/src/building/sim.rs | 2 +- .../src/building/testing/bundle_tests/mod.rs | 3 +- .../building/testing/bundle_tests/setup.rs | 2 +- .../testing/evm_inspector_tests/setup.rs | 3 +- .../src/building/testing/test_chain_state.rs | 35 +- crates/rbuilder/src/integration/playground.rs | 2 +- crates/rbuilder/src/integration/simple.rs | 2 +- .../rbuilder/src/live_builder/base_config.rs | 33 +- .../block_output/bidding/interfaces.rs | 3 +- .../bidding/wallet_balance_watcher.rs | 7 +- .../block_sealing_bidder_factory.rs | 3 +- .../live_builder/block_output/relay_submit.rs | 4 +- .../rbuilder/src/live_builder/building/mod.rs | 7 +- crates/rbuilder/src/live_builder/cli.rs | 15 +- crates/rbuilder/src/live_builder/config.rs | 48 +- crates/rbuilder/src/live_builder/mod.rs | 31 +- .../src/live_builder/order_input/orderpool.rs | 3 +- .../live_builder/order_input/rpc_server.rs | 3 +- .../order_input/txpool_fetcher.rs | 16 +- .../src/live_builder/payload_events/mod.rs | 5 +- .../payload_events/payload_source.rs | 2 +- .../src/live_builder/simulation/mod.rs | 2 +- .../src/live_builder/simulation/sim_worker.rs | 2 +- crates/rbuilder/src/mev_boost/rpc.rs | 4 +- crates/rbuilder/src/mev_boost/sign_payload.rs | 42 +- crates/rbuilder/src/primitives/fmt.rs | 4 +- crates/rbuilder/src/primitives/mod.rs | 33 +- crates/rbuilder/src/primitives/serialize.rs | 11 +- .../src/primitives/test_data_generator.rs | 3 +- crates/rbuilder/src/roothash/mod.rs | 56 +- crates/rbuilder/src/roothash/prefetcher.rs | 8 +- crates/rbuilder/src/utils/mod.rs | 4 +- .../src/utils/provider_factory_reopen.rs | 75 +- crates/rbuilder/src/utils/test_utils.rs | 2 +- crates/rbuilder/src/utils/tx_signer.rs | 19 +- crates/reth-rbuilder/Cargo.toml | 4 +- crates/reth-rbuilder/src/main.rs | 130 +- crates/transaction-pool-bundle-ext/Cargo.toml | 7 +- .../bundle_pool_ops/rbuilder/Cargo.toml | 9 +- .../bundle_pool_ops/rbuilder/src/lib.rs | 14 +- .../src/bundle_supported_pool.rs | 99 +- .../transaction-pool-bundle-ext/src/traits.rs | 4 +- 94 files changed, 4082 insertions(+), 2783 deletions(-) create mode 100644 crates/rbuilder/benches/blob_data/blob1.json delete mode 100644 crates/rbuilder/benches/blob_data/blob1.txt diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index 15443eec..c09cbb8c 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -66,7 +66,6 @@ jobs: integration: name: Integration tests runs-on: warp-ubuntu-latest-x64-16x - needs: lint_and_test strategy: matrix: toolchain: @@ -78,6 +77,12 @@ jobs: - name: Checkout sources uses: actions/checkout@v4 + # https://github.com/dtolnay/rust-toolchain + - name: Setup rust toolchain + uses: dtolnay/rust-toolchain@stable + with: + toolchain: ${{ matrix.toolchain }} + - name: Download builder playground uses: flashbots/flashbots-toolchain@v0.1 with: diff --git a/Cargo.lock b/Cargo.lock index 05f52404..46b598fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,18 +4,18 @@ version = 3 [[package]] name = "addr2line" -version = "0.22.0" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] [[package]] -name = "adler" -version = "1.0.2" +name = "adler2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "aead" @@ -91,16 +91,17 @@ dependencies = [ [[package]] name = "allocator-api2" -version = "0.2.18" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" [[package]] name = "alloy-chains" -version = "0.1.23" +version = "0.1.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1752d7d62e2665da650a36d84abbf239f812534475d51f072a49a533513b7cdd" +checksum = "18c5c520273946ecf715c0010b4e3503d7eba9893cd9ce6b7fff5654c4a3c470" dependencies = [ + "alloy-primitives 0.8.12", "alloy-rlp", "arbitrary", "num_enum", @@ -111,35 +112,38 @@ dependencies = [ [[package]] name = "alloy-consensus" -version = "0.3.1" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4177d135789e282e925092be8939d421b701c6d92c0a16679faa659d9166289d" +checksum = "41ed961a48297c732a5d97ee321aa8bb5009ecadbcb077d8bec90cb54e651629" dependencies = [ "alloy-eips", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", "alloy-rlp", "alloy-serde", "arbitrary", + "auto_impl", "c-kzg", + "derive_more 1.0.0", "serde", + "serde_with", ] [[package]] name = "alloy-dyn-abi" -version = "0.8.0" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba5b68572f5dfa99ede0a491d658c9842626c956b840d0b97d0bbc9637742504" +checksum = "ef2364c782a245cf8725ea6dbfca5f530162702b5d685992ea03ce64529136cc" dependencies = [ "alloy-json-abi", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", "alloy-sol-type-parser", "alloy-sol-types", "const-hex", - "derive_more 0.99.18", + "derive_more 1.0.0", "itoa", "serde", "serde_json", - "winnow 0.6.15", + "winnow", ] [[package]] @@ -148,7 +152,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0069cf0642457f87a01a014f6dc29d5d893cd4fd8fddf0c3cdfad1bb3ebafc41" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", "alloy-rlp", "arbitrary", "rand 0.8.5", @@ -157,27 +161,29 @@ dependencies = [ [[package]] name = "alloy-eip7702" -version = "0.1.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d319bb544ca6caeab58c39cea8921c55d924d4f68f2c60f24f914673f9a74a" +checksum = "64ffc577390ce50234e02d841214b3dc0bea6aaaae8e04bbf3cb82e9a45da9eb" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", "alloy-rlp", "arbitrary", - "k256 0.13.3", + "derive_more 1.0.0", + "k256 0.13.4", "rand 0.8.5", "serde", + "serde_with", ] [[package]] name = "alloy-eips" -version = "0.3.6" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f923dd5fca5f67a43d81ed3ebad0880bd41f6dd0ada930030353ac356c54cd0f" +checksum = "b69e06cf9c37be824b9d26d6d101114fdde6af0c87de2828b414c05c4b3daa71" dependencies = [ "alloy-eip2930", "alloy-eip7702", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", "alloy-rlp", "alloy-serde", "arbitrary", @@ -192,22 +198,22 @@ dependencies = [ [[package]] name = "alloy-genesis" -version = "0.3.1" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b85dfc693e4a1193f0372a8f789df12ab51fcbe7be0733baa04939a86dd813b" +checksum = "dde15e14944a88bd6a57d325e9a49b75558746fe16aaccc79713ae50a6a9574c" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", "alloy-serde", "serde", ] [[package]] name = "alloy-json-abi" -version = "0.8.0" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "299d2a937b6c60968df3dad2a988b0f0e03277b344639a4f7a31bd68e6285e59" +checksum = "b84c506bf264110fa7e90d9924f742f40ef53c6572ea56a0b0bd714a567ed389" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", "alloy-sol-type-parser", "serde", "serde_json", @@ -215,29 +221,29 @@ dependencies = [ [[package]] name = "alloy-json-rpc" -version = "0.3.1" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4207166c79cfdf7f3bed24bbc84f5c7c5d4db1970f8c82e3fcc76257f16d2166" +checksum = "af5979e0d5a7bf9c7eb79749121e8256e59021af611322aee56e77e20776b4b3" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", "alloy-sol-types", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "tracing", ] [[package]] name = "alloy-network" -version = "0.3.1" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe2802d5b8c632f18d68c352073378f02a3407c1b6a4487194e7d21ab0f002" +checksum = "204237129086ce5dc17a58025e93739b01b45313841f98fa339eb1d780511e57" dependencies = [ "alloy-consensus", "alloy-eips", "alloy-json-rpc", "alloy-network-primitives", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", "alloy-rpc-types-eth", "alloy-serde", "alloy-signer", @@ -245,32 +251,35 @@ dependencies = [ "async-trait", "auto_impl", "futures-utils-wasm", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "alloy-network-primitives" -version = "0.3.1" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "396c07726030fa0f9dab5da8c71ccd69d5eb74a7fe1072b7ae453a67e4fe553e" +checksum = "514f70ee2a953db21631cd817b13a1571474ec77ddc03d47616d5e8203489fde" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-consensus", + "alloy-eips", + "alloy-primitives 0.8.12", "alloy-serde", "serde", ] [[package]] name = "alloy-node-bindings" -version = "0.3.1" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c847311cc7386684ef38ab404069d795bee07da945f63d884265436870a17276" +checksum = "27444ea67d360508753022807cdd0b49a95c878924c9c5f8f32668b7d7768245" dependencies = [ "alloy-genesis", - "alloy-primitives 0.8.0", - "k256 0.13.3", + "alloy-primitives 0.8.12", + "k256 0.13.4", + "rand 0.8.5", "serde_json", "tempfile", - "thiserror", + "thiserror 1.0.69", "tracing", "url", ] @@ -288,7 +297,7 @@ dependencies = [ "derive_more 0.99.18", "hex-literal", "itoa", - "k256 0.13.3", + "k256 0.13.4", "keccak-asm", "proptest", "rand 0.8.5", @@ -299,9 +308,9 @@ dependencies = [ [[package]] name = "alloy-primitives" -version = "0.8.0" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a767e59c86900dd7c3ce3ecef04f3ace5ac9631ee150beb8b7d22f7fa3bbb2d7" +checksum = "9fce5dbd6a4f118eecc4719eaa9c7ffc31c315e6c5ccde3642db927802312425" dependencies = [ "alloy-rlp", "arbitrary", @@ -309,25 +318,31 @@ dependencies = [ "cfg-if", "const-hex", "derive_arbitrary", - "derive_more 0.99.18", + "derive_more 1.0.0", + "foldhash", "getrandom 0.2.15", + "hashbrown 0.15.1", "hex-literal", + "indexmap 2.6.0", "itoa", - "k256 0.13.3", + "k256 0.13.4", "keccak-asm", + "paste", "proptest", "proptest-derive", "rand 0.8.5", "ruint", + "rustc-hash 2.0.0", "serde", + "sha3", "tiny-keccak", ] [[package]] name = "alloy-provider" -version = "0.3.1" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1376948df782ffee83a54cac4b2aba14134edd997229a3db97da0a606586eb5c" +checksum = "4814d141ede360bb6cd1b4b064f1aab9de391e7c4d0d4d50ac89ea4bc1e25fbd" dependencies = [ "alloy-chains", "alloy-consensus", @@ -335,7 +350,7 @@ dependencies = [ "alloy-json-rpc", "alloy-network", "alloy-network-primitives", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", "alloy-pubsub", "alloy-rpc-client", "alloy-rpc-types-eth", @@ -350,24 +365,27 @@ dependencies = [ "futures", "futures-utils-wasm", "lru", + "parking_lot", "pin-project", - "reqwest 0.12.8", + "reqwest 0.12.9", + "schnellru", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "tokio", "tracing", "url", + "wasmtimer", ] [[package]] name = "alloy-pubsub" -version = "0.3.1" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa73f976e7b6341f3f8a404241cf04f883d40212cd4f2633c66d99de472e262c" +checksum = "96ba46eb69ddf7a9925b81f15229cb74658e6eebe5dd30a5b74e2cd040380573" dependencies = [ "alloy-json-rpc", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", "alloy-transport", "bimap", "futures", @@ -375,15 +393,15 @@ dependencies = [ "serde_json", "tokio", "tokio-stream", - "tower", + "tower 0.5.1", "tracing", ] [[package]] name = "alloy-rlp" -version = "0.3.7" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a43b18702501396fa9bcdeecd533bc85fac75150d308fc0f6800a01e6234a003" +checksum = "da0822426598f95e45dd1ea32a738dac057529a709ee645fcc516ffa4cbde08f" dependencies = [ "alloy-rlp-derive", "arrayvec", @@ -392,23 +410,23 @@ dependencies = [ [[package]] name = "alloy-rlp-derive" -version = "0.3.7" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d83524c1f6162fcb5b0decf775498a125066c86dda6066ed609531b0e912f85a" +checksum = "2b09cae092c27b6f1bde952653a22708691802e57bfef4a2973b80bea21efd3f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.87", ] [[package]] name = "alloy-rpc-client" -version = "0.3.1" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02378418a429f8a14a0ad8ffaa15b2d25ff34914fc4a1e366513c6a3800e03b3" +checksum = "7fc2bd1e7403463a5f2c61e955bcc9d3072b63aa177442b0f9aa6a6d22a941e3" dependencies = [ "alloy-json-rpc", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", "alloy-pubsub", "alloy-transport", "alloy-transport-http", @@ -416,116 +434,129 @@ dependencies = [ "alloy-transport-ws", "futures", "pin-project", - "reqwest 0.12.8", + "reqwest 0.12.9", "serde", "serde_json", "tokio", "tokio-stream", - "tower", + "tower 0.5.1", "tracing", "url", + "wasmtimer", ] [[package]] name = "alloy-rpc-types" -version = "0.3.1" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9ae4c4fbd37d9996f501fbc7176405aab97ae3a5772789be06ef0e7c4dad6dd" +checksum = "eea9bf1abdd506f985a53533f5ac01296bcd6102c5e139bbc5d40bc468d2c916" dependencies = [ + "alloy-primitives 0.8.12", "alloy-rpc-types-engine", "alloy-rpc-types-eth", - "alloy-rpc-types-trace", "alloy-serde", "serde", ] [[package]] name = "alloy-rpc-types-admin" -version = "0.3.1" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "594b7cb723759c7b438c95a3bbd2e391760c03ee857443070758aaf2593ae84e" +checksum = "ea02c25541fb19eaac4278aa5c41d2d7e0245898887e54a74bfc0f3103e99415" dependencies = [ "alloy-genesis", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", "serde", "serde_json", ] [[package]] name = "alloy-rpc-types-anvil" -version = "0.3.1" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "140b079c6fda14d9586432bf988b46ac0e04871ca313c9e00aa85cc808105e8a" +checksum = "2382fc63fb0cf3e02818d547b80cb66cc49a31f8803d0c328402b2008bc13650" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", "alloy-serde", "serde", ] [[package]] name = "alloy-rpc-types-beacon" -version = "0.3.6" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e7081d2206dca51ce23a06338d78d9b536931cc3f15134fc1c6535eb2b77f18" +checksum = "45357a642081c8ce235c0ad990c4e9279f5f18a723545076b38cfcc05cc25234" dependencies = [ "alloy-eips", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", "alloy-rpc-types-engine", "ethereum_ssz", "ethereum_ssz_derive", "serde", "serde_with", - "thiserror", + "thiserror 1.0.69", +] + +[[package]] +name = "alloy-rpc-types-debug" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5afe3ab1038f90faf56304aa0adf1e6a8c9844615d8f83967f932f3a70390b1" +dependencies = [ + "alloy-primitives 0.8.12", + "serde", ] [[package]] name = "alloy-rpc-types-engine" -version = "0.3.6" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1464c4dd646e1bdfde86ae65ce5ba168dbb29180b478011fe87117ae46b1629b" +checksum = "886d22d41992287a235af2f3af4299b5ced2bcafb81eb835572ad35747476946" dependencies = [ "alloy-consensus", "alloy-eips", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", "alloy-rlp", "alloy-serde", "derive_more 1.0.0", "ethereum_ssz", "ethereum_ssz_derive", - "jsonrpsee-types 0.24.4", + "jsonrpsee-types 0.24.7", "jsonwebtoken", "rand 0.8.5", "serde", + "strum", ] [[package]] name = "alloy-rpc-types-eth" -version = "0.3.1" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15bb3506ab1cf415d4752778c93e102050399fb8de97b7da405a5bf3e31f5f3b" +checksum = "00b034779a4850b4b03f5be5ea674a1cf7d746b2da762b34d1860ab45e48ca27" dependencies = [ "alloy-consensus", "alloy-eips", "alloy-network-primitives", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", "alloy-rlp", "alloy-serde", "alloy-sol-types", + "arbitrary", + "derive_more 1.0.0", "itertools 0.13.0", - "jsonrpsee-types 0.24.4", + "jsonrpsee-types 0.24.7", "serde", "serde_json", - "thiserror", ] [[package]] name = "alloy-rpc-types-mev" -version = "0.3.1" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e8cb848b66617f7d58b576bfc416854c4e9ae8d35e14f5077c0c779048f280" +checksum = "3246948dfa5f5060a9abe04233d741ea656ef076b12958f3242416ce9f375058" dependencies = [ "alloy-eips", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", "alloy-serde", "serde", "serde_json", @@ -533,25 +564,25 @@ dependencies = [ [[package]] name = "alloy-rpc-types-trace" -version = "0.3.1" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16cca915e0aab3b2657b4f9efe02eb88e5483905fb6d244749652aae14e5f92e" +checksum = "4e5fb6c5c401321f802f69dcdb95b932f30f8158f6798793f914baac5995628e" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", "alloy-rpc-types-eth", "alloy-serde", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "alloy-rpc-types-txpool" -version = "0.3.1" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68eede4bd722bb872222efbbfbccc8f9b86e597143934b8ce556d3e0487bb662" +checksum = "9ad066b49c3b1b5f64cdd2399177a19926a6a15db2dbf11e2098de621f9e7480" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", "alloy-rpc-types-eth", "alloy-serde", "serde", @@ -559,11 +590,11 @@ dependencies = [ [[package]] name = "alloy-serde" -version = "0.3.1" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae417978015f573b4a8c02af17f88558fb22e3fccd12e8a910cf6a2ff331cfcb" +checksum = "028e72eaa9703e4882344983cfe7636ce06d8cce104a78ea62fd19b46659efc4" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", "arbitrary", "serde", "serde_json", @@ -571,99 +602,99 @@ dependencies = [ [[package]] name = "alloy-signer" -version = "0.3.1" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b750c9b61ac0646f8f4a61231c2732a337b2c829866fc9a191b96b7eedf80ffe" +checksum = "592c185d7100258c041afac51877660c7bf6213447999787197db4842f0e938e" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", "async-trait", "auto_impl", "elliptic-curve 0.13.8", - "k256 0.13.3", - "thiserror", + "k256 0.13.4", + "thiserror 1.0.69", ] [[package]] name = "alloy-signer-local" -version = "0.3.1" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c640f9343e8f741f837c345c5ea30239ba77938b3691b884c736834853bd16c" +checksum = "6614f02fc1d5b079b2a4a5320018317b506fd0a6d67c1fd5542a71201724986c" dependencies = [ "alloy-consensus", "alloy-network", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", "alloy-signer", "async-trait", - "k256 0.13.3", + "k256 0.13.4", "rand 0.8.5", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "alloy-sol-macro" -version = "0.8.0" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "183bcfc0f3291d9c41a3774172ee582fb2ce6eb6569085471d8f225de7bb86fc" +checksum = "9343289b4a7461ed8bab8618504c995c049c082b70c7332efd7b32125633dc05" dependencies = [ "alloy-sol-macro-expander", "alloy-sol-macro-input", - "proc-macro-error", + "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.87", ] [[package]] name = "alloy-sol-macro-expander" -version = "0.8.0" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71c4d842beb7a6686d04125603bc57614d5ed78bf95e4753274db3db4ba95214" +checksum = "4222d70bec485ceccc5d8fd4f2909edd65b5d5e43d4aca0b5dcee65d519ae98f" dependencies = [ "alloy-sol-macro-input", "const-hex", "heck 0.5.0", - "indexmap 2.2.6", - "proc-macro-error", + "indexmap 2.6.0", + "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.87", "syn-solidity", "tiny-keccak", ] [[package]] name = "alloy-sol-macro-input" -version = "0.8.0" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1306e8d3c9e6e6ecf7a39ffaf7291e73a5f655a2defd366ee92c2efebcdf7fee" +checksum = "2e17f2677369571b976e51ea1430eb41c3690d344fef567b840bfc0b01b6f83a" dependencies = [ "const-hex", "dunce", "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.87", "syn-solidity", ] [[package]] name = "alloy-sol-type-parser" -version = "0.8.0" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4691da83dce9c9b4c775dd701c87759f173bd3021cbf2e60cde00c5fe6d7241" +checksum = "aa64d80ae58ffaafdff9d5d84f58d03775f66c84433916dc9a64ed16af5755da" dependencies = [ "serde", - "winnow 0.6.15", + "winnow", ] [[package]] name = "alloy-sol-types" -version = "0.8.0" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "577e262966e92112edbd15b1b2c0947cc434d6e8311df96d3329793fe8047da9" +checksum = "6520d427d4a8eb7aa803d852d7a52ceb0c519e784c292f64bb339e636918cf27" dependencies = [ "alloy-json-abi", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", "alloy-sol-macro", "const-hex", "serde", @@ -671,9 +702,9 @@ dependencies = [ [[package]] name = "alloy-transport" -version = "0.3.1" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2799749ca692ae145f54968778877afd7c95e788488f176cfdfcf2a8abeb2062" +checksum = "be77579633ebbc1266ae6fd7694f75c408beb1aeb6865d0b18f22893c265a061" dependencies = [ "alloy-json-rpc", "base64 0.22.1", @@ -681,33 +712,34 @@ dependencies = [ "futures-utils-wasm", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "tokio", - "tower", + "tower 0.5.1", "tracing", "url", + "wasmtimer", ] [[package]] name = "alloy-transport-http" -version = "0.3.1" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc10c4dd932f66e0db6cc5735241e0c17a6a18564b430bbc1839f7db18587a93" +checksum = "91fd1a5d0827939847983b46f2f79510361f901dc82f8e3c38ac7397af142c6e" dependencies = [ "alloy-json-rpc", "alloy-transport", - "reqwest 0.12.8", + "reqwest 0.12.9", "serde_json", - "tower", + "tower 0.5.1", "tracing", "url", ] [[package]] name = "alloy-transport-ipc" -version = "0.3.1" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f39f88798c3282914079a3eda3ea8b9fbf21e383a0ce85958b4f1c170d222f" +checksum = "8073d1186bfeeb8fbdd1292b6f1a0731f3aed8e21e1463905abfae0b96a887a6" dependencies = [ "alloy-json-rpc", "alloy-pubsub", @@ -724,34 +756,34 @@ dependencies = [ [[package]] name = "alloy-transport-ws" -version = "0.3.1" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65e732028930aa17b7edd464a9711365417635e984028fcc7176393ccea22c00" +checksum = "61f27837bb4a1d6c83a28231c94493e814882f0e9058648a97e908a5f3fc9fcf" dependencies = [ "alloy-pubsub", "alloy-transport", "futures", "http 1.1.0", - "rustls 0.23.12", + "rustls 0.23.16", "serde_json", "tokio", - "tokio-tungstenite 0.23.1", + "tokio-tungstenite 0.24.0", "tracing", "ws_stream_wasm", ] [[package]] name = "alloy-trie" -version = "0.5.1" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "398a977d774db13446b8cead8cfa9517aebf9e03fc8a1512892dc1e03e70bb04" +checksum = "b6b2e366c0debf0af77766c23694a3f863b02633050e71e096e257ffbd395e50" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", "alloy-rlp", "arbitrary", + "arrayvec", "derive_arbitrary", "derive_more 1.0.0", - "hashbrown 0.14.5", "nybbles", "proptest", "proptest-derive", @@ -783,9 +815,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstream" -version = "0.6.14" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", @@ -798,63 +830,63 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.8" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.3" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anyhow" -version = "1.0.86" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" [[package]] name = "aquamarine" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21cc1548309245035eb18aa7f0967da6bc65587005170c56e6ef2788a4cf3f4e" +checksum = "0f50776554130342de4836ba542aa85a4ddb361690d7e8df13774d7284c3d5c2" dependencies = [ "include_dir", "itertools 0.10.5", - "proc-macro-error", + "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.87", ] [[package]] name = "arbitrary" -version = "1.3.2" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" +checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" dependencies = [ "derive_arbitrary", ] @@ -902,7 +934,7 @@ dependencies = [ "num-bigint", "num-traits", "paste", - "rustc_version 0.4.0", + "rustc_version 0.4.1", "zeroize", ] @@ -1000,15 +1032,18 @@ checksum = "bf7d0a018de4f6aa429b9d33d69edf69072b1c5b1cb8d3e4a5f7ef898fc3eb76" [[package]] name = "arrayref" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d151e35f61089500b617991b791fc8bfd237ae50cd5950803758a179b41e67a" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] name = "arrayvec" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +dependencies = [ + "serde", +] [[package]] name = "arrow-format" @@ -1046,7 +1081,7 @@ dependencies = [ "parquet2", "regex", "regex-syntax 0.6.29", - "rustc_version 0.4.0", + "rustc_version 0.4.1", "simdutf8", "streaming-iterator", "strength_reduce", @@ -1072,18 +1107,18 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.4.12" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fec134f64e2bc57411226dfc4e52dec859ddfc7e711fc5e07b612584f000e4aa" +checksum = "0cb8f1d480b0ea3783ab015936d2a55c87e219676f0c0b7dec61494043f21857" dependencies = [ - "brotli 6.0.0", + "brotli 7.0.0", "flate2", "futures-core", "memchr", "pin-project-lite", "tokio", "zstd 0.13.2", - "zstd-safe 7.2.0", + "zstd-safe 7.2.1", ] [[package]] @@ -1111,9 +1146,9 @@ dependencies = [ [[package]] name = "async-stream" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" dependencies = [ "async-stream-impl", "futures-core", @@ -1122,13 +1157,13 @@ dependencies = [ [[package]] name = "async-stream-impl" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.87", ] [[package]] @@ -1139,7 +1174,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.87", ] [[package]] @@ -1150,7 +1185,7 @@ checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c" dependencies = [ "futures", "pharos", - "rustc_version 0.4.0", + "rustc_version 0.4.1", ] [[package]] @@ -1197,40 +1232,38 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.87", ] [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[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 2.2.0", "tokio", ] [[package]] name = "backtrace" -version = "0.3.73" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", + "windows-targets 0.52.6", ] [[package]] @@ -1280,7 +1313,7 @@ name = "beacon-api-client" version = "0.1.0" source = "git+https://github.com/ralexstokes/ethereum-consensus/?rev=cf3c404043230559660810bc0c9d6d5a8498d819#cf3c404043230559660810bc0c9d6d5a8498d819" dependencies = [ - "clap 4.5.19", + "clap 4.5.21", "ethereum-consensus", "http 0.2.12", "itertools 0.10.5", @@ -1288,7 +1321,7 @@ dependencies = [ "reqwest 0.11.27", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "tokio", "tracing", "url", @@ -1316,9 +1349,9 @@ dependencies = [ [[package]] name = "bigdecimal" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d712318a27c7150326677b321a5fa91b55f6d9034ffd67f20319e147d40cee" +checksum = "8f850665a0385e070b64c38d2354e6c104c8479c59868d1e48a0c13ee2c7a1c1" dependencies = [ "autocfg", "libm", @@ -1344,30 +1377,22 @@ dependencies = [ [[package]] name = "bindgen" -version = "0.69.4" +version = "0.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0" +checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" dependencies = [ "bitflags 2.6.0", "cexpr", "clang-sys", "itertools 0.11.0", - "lazy_static", - "lazycell", "proc-macro2", "quote", "regex", "rustc-hash 1.1.0", "shlex", - "syn 2.0.72", + "syn 2.0.87", ] -[[package]] -name = "binout" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b60b1af88a588fca5fe424ae7d735bc52814f80ff57614f57043cc4e2024f2ea" - [[package]] name = "bit-set" version = "0.5.3" @@ -1399,15 +1424,6 @@ dependencies = [ "serde", ] -[[package]] -name = "bitm" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06e8e5bec3490b9f6f3adbb78aa4f53e8396fd9994e8a62a346b44ea7c15f35" -dependencies = [ - "dyn_size_of", -] - [[package]] name = "bitvec" version = "1.0.1" @@ -1460,6 +1476,144 @@ dependencies = [ "zeroize", ] +[[package]] +name = "boa_ast" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a69ee3a749ea36d4e56d92941e7b25076b493d4917c3d155b6cf369e23547d9" +dependencies = [ + "bitflags 2.6.0", + "boa_interner", + "boa_macros", + "indexmap 2.6.0", + "num-bigint", + "rustc-hash 2.0.0", +] + +[[package]] +name = "boa_engine" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06e4559b35b80ceb2e6328481c0eca9a24506663ea33ee1e279be6b5b618b25c" +dependencies = [ + "arrayvec", + "bitflags 2.6.0", + "boa_ast", + "boa_gc", + "boa_interner", + "boa_macros", + "boa_parser", + "boa_profiler", + "boa_string", + "bytemuck", + "cfg-if", + "dashmap 5.5.3", + "fast-float", + "hashbrown 0.14.5", + "icu_normalizer", + "indexmap 2.6.0", + "intrusive-collections", + "itertools 0.13.0", + "num-bigint", + "num-integer", + "num-traits", + "num_enum", + "once_cell", + "pollster", + "portable-atomic", + "rand 0.8.5", + "regress", + "rustc-hash 2.0.0", + "ryu-js", + "serde", + "serde_json", + "sptr", + "static_assertions", + "tap", + "thin-vec", + "thiserror 1.0.69", + "time", +] + +[[package]] +name = "boa_gc" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "716406f57d67bc3ac7fd227d5513b42df401dff14a3be22cbd8ee29817225363" +dependencies = [ + "boa_macros", + "boa_profiler", + "boa_string", + "hashbrown 0.14.5", + "thin-vec", +] + +[[package]] +name = "boa_interner" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e18df2272616e1ba0322a69333d37dbb78797f1aa0595aad9dc41e8ecd06ad9" +dependencies = [ + "boa_gc", + "boa_macros", + "hashbrown 0.14.5", + "indexmap 2.6.0", + "once_cell", + "phf 0.11.2", + "rustc-hash 2.0.0", + "static_assertions", +] + +[[package]] +name = "boa_macros" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240f4126219a83519bad05c9a40bfc0303921eeb571fc2d7e44c17ffac99d3f1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", + "synstructure 0.13.1", +] + +[[package]] +name = "boa_parser" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b59dc05bf1dc019b11478a92986f590cff43fced4d20e866eefb913493e91c" +dependencies = [ + "bitflags 2.6.0", + "boa_ast", + "boa_interner", + "boa_macros", + "boa_profiler", + "fast-float", + "icu_properties", + "num-bigint", + "num-traits", + "regress", + "rustc-hash 2.0.0", +] + +[[package]] +name = "boa_profiler" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00ee0645509b3b91abd724f25072649d9e8e65653a78ff0b6e592788a58dd838" + +[[package]] +name = "boa_string" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae85205289bab1f2c7c8a30ddf0541cf89ba2ff7dbd144feef50bbfa664288d4" +dependencies = [ + "fast-float", + "paste", + "rustc-hash 2.0.0", + "sptr", + "static_assertions", +] + [[package]] name = "boyer-moore-magiclen" version = "0.2.20" @@ -1482,9 +1636,9 @@ dependencies = [ [[package]] name = "brotli" -version = "6.0.0" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74f7971dbd9326d58187408ab83117d8ac1bb9c17b085fdacd1cf2f598719b6b" +checksum = "cc97b8f16f944bba54f0433f07e30be199b6dc2bd25937444bbad560bcea29bd" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -1528,20 +1682,20 @@ dependencies = [ [[package]] name = "bstr" -version = "1.9.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706" +checksum = "1a68f1f47cdf0ec8ee4b941b2eee2a80cb796db73118c0dd09ac63fbe405be22" dependencies = [ "memchr", - "regex-automata 0.4.7", + "regex-automata 0.4.9", "serde", ] [[package]] name = "built" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "236e6289eda5a812bc6b53c3b024039382a2895fbbeef2d748b2931546d392c4" +checksum = "c360505aed52b7ec96a3636c3f039d99103c37d1d9b4f7a8c743d3ea9ffcd03b" dependencies = [ "chrono", "git2", @@ -1561,22 +1715,22 @@ checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" [[package]] name = "bytemuck" -version = "1.16.1" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b236fc92302c97ed75b38da1f4917b5cdda4984745740f153a5d3059e48d725e" +checksum = "8334215b81e418a0a7bdb8ef0849474f40bb10c8b71f1c4ed315cff49f32494d" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ee891b04274a59bd38b412188e24b849617b2e45a0fd8d057deb63e7403761b" +checksum = "bcfcc3cd946cb52f0bbfdbbcfa2f4e24f75ebb6c0e1002f7c25904fada18b9ec" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.87", ] [[package]] @@ -1587,9 +1741,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.6.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12916984aab3fa6e39d655a33e09c0071eb36d6ab3aea5c2d78551f1df6d952" +checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" dependencies = [ "serde", ] @@ -1632,9 +1786,9 @@ dependencies = [ [[package]] name = "camino" -version = "1.1.7" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239" +checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" dependencies = [ "serde", ] @@ -1659,7 +1813,7 @@ dependencies = [ "semver 1.0.23", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -1685,12 +1839,13 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.6" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aba8f4e9906c7ce3c73463f62a7f0c65183ada1a2d47e397cc8810827f9694f" +checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47" dependencies = [ "jobserver", "libc", + "shlex", ] [[package]] @@ -1714,6 +1869,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "chrono" version = "0.4.38" @@ -1791,9 +1952,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.19" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7be5744db7978a28d9df86a214130d106a89ce49644cbc4e3f0c22c3fba30615" +checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" dependencies = [ "clap_builder", "clap_derive", @@ -1801,13 +1962,13 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.19" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5fbc17d3ef8278f55b282b2a2e75ae6f6c7d4bb70ed3d0382375104bfafdb4b" +checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" dependencies = [ "anstream", "anstyle", - "clap_lex 0.7.1", + "clap_lex 0.7.3", "strsim", ] @@ -1820,7 +1981,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.87", ] [[package]] @@ -1834,15 +1995,15 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.1" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" +checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" [[package]] name = "colorchoice" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "combine" @@ -1856,25 +2017,26 @@ dependencies = [ [[package]] name = "comfy-table" -version = "7.1.1" +version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b34115915337defe99b2aff5c2ce6771e5fbc4079f4b506301f5cf394c8452f7" +checksum = "24f165e7b643266ea80cb858aed492ad9280e3e05ce24d4a99d7d7b889b6a4d9" dependencies = [ "crossterm", "strum", "strum_macros 0.26.4", - "unicode-width", + "unicode-width 0.2.0", ] [[package]] name = "compact_str" -version = "0.7.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f86b9c4c00838774a6d902ef931eff7470720c51d90c2e32cfe15dc304737b3f" +checksum = "6050c3a16ddab2e412160b31f2c871015704239bca62f72f6e5f0be631d3f644" dependencies = [ "castaway", "cfg-if", "itoa", + "rustversion", "ryu", "static_assertions", ] @@ -1906,15 +2068,15 @@ dependencies = [ "encode_unicode", "lazy_static", "libc", - "unicode-width", + "unicode-width 0.1.14", "windows-sys 0.52.0", ] [[package]] name = "const-hex" -version = "1.12.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94fb8a24a26d37e1ffd45343323dc9fe6654ceea44c12f2fcb3d7ac29e610bc6" +checksum = "0121754e84117e65f9d90648ee6aa4882a6e63110307ab73967a4c5e7e69e586" dependencies = [ "cfg-if", "cpufeatures", @@ -1931,9 +2093,9 @@ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "const_format" -version = "0.2.32" +version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3a214c7af3d04997541b18d432afaff4c455e79e2029079647e72fc2bd27673" +checksum = "50c655d81ff1114fb0dcdea9225ea9f0cc712a6f8d189378e82bdf62a473a64b" dependencies = [ "const_format_proc_macros", "konst", @@ -1941,9 +2103,9 @@ dependencies = [ [[package]] name = "const_format_proc_macros" -version = "0.2.32" +version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7f6ff08fd20f4f299298a28e2dfa8a8ba1036e6cd2460ac1de7b425d76f2500" +checksum = "eff1a44b93f47b1bac19a27932f5c591e43d1ba357ee4f61526c8a25603f0eb1" dependencies = [ "proc-macro2", "quote", @@ -1983,9 +2145,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "core2" @@ -1998,9 +2160,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "0ca741a962e1b0bff6d724a1a0958b686406e853bb14061f218562e1896f95e6" dependencies = [ "libc", ] @@ -2064,7 +2226,7 @@ dependencies = [ "anes", "cast", "ciborium", - "clap 4.5.19", + "clap 4.5.21", "criterion-plot", "futures", "is-terminal", @@ -2093,6 +2255,12 @@ dependencies = [ "itertools 0.10.5", ] +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + [[package]] name = "crossbeam" version = "0.8.4" @@ -2151,15 +2319,15 @@ checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crossterm" -version = "0.27.0" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df" +checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" dependencies = [ "bitflags 2.6.0", "crossterm_winapi", - "libc", - "mio 0.8.11", - "parking_lot 0.12.3", + "mio 1.0.2", + "parking_lot", + "rustix", "signal-hook", "signal-hook-mio", "winapi", @@ -2234,7 +2402,7 @@ dependencies = [ "cssparser-macros", "dtoa-short", "itoa", - "phf 0.11.2", + "phf 0.10.1", "smallvec", ] @@ -2245,14 +2413,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" dependencies = [ "quote", - "syn 2.0.72", + "syn 2.0.87", ] [[package]] name = "csv" -version = "1.3.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe" +checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf" dependencies = [ "csv-core", "itoa", @@ -2276,7 +2444,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f" dependencies = [ "quote", - "syn 2.0.72", + "syn 2.0.87", ] [[package]] @@ -2288,20 +2456,6 @@ dependencies = [ "cipher", ] -[[package]] -name = "cuckoofilter" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b810a8449931679f64cd7eef1bbd0fa315801b6d5d9cdc1ace2804d6529eee18" -dependencies = [ - "byteorder", - "fnv", - "rand 0.7.3", - "serde", - "serde_bytes", - "serde_derive", -] - [[package]] name = "curve25519-dalek" version = "4.1.3" @@ -2313,7 +2467,7 @@ dependencies = [ "curve25519-dalek-derive", "digest 0.10.7", "fiat-crypto", - "rustc_version 0.4.0", + "rustc_version 0.4.1", "subtle", "zeroize", ] @@ -2326,7 +2480,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.87", ] [[package]] @@ -2350,7 +2504,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.72", + "syn 2.0.87", ] [[package]] @@ -2361,7 +2515,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.72", + "syn 2.0.87", ] [[package]] @@ -2374,7 +2528,7 @@ dependencies = [ "hashbrown 0.14.5", "lock_api", "once_cell", - "parking_lot_core 0.9.10", + "parking_lot_core", ] [[package]] @@ -2388,7 +2542,8 @@ dependencies = [ "hashbrown 0.14.5", "lock_api", "once_cell", - "parking_lot_core 0.9.10", + "parking_lot_core", + "serde", ] [[package]] @@ -2425,11 +2580,12 @@ checksum = "f578e8e2c440e7297e008bb5486a3a8a194775224bbc23729b0dbdfaeebf162e" [[package]] name = "delay_map" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4355c25cbf99edcb6b4a0e906f6bdc6956eda149e84455bea49696429b2f8e8" +checksum = "df941644b671f05f59433e481ba0d31ac10e3667de725236a4c0d587c496fba1" dependencies = [ "futures", + "tokio", "tokio-util", ] @@ -2477,13 +2633,13 @@ dependencies = [ [[package]] name = "derive_arbitrary" -version = "1.3.2" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" +checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.87", ] [[package]] @@ -2495,8 +2651,8 @@ dependencies = [ "convert_case 0.4.0", "proc-macro2", "quote", - "rustc_version 0.4.0", - "syn 2.0.72", + "rustc_version 0.4.1", + "syn 2.0.87", ] [[package]] @@ -2517,10 +2673,16 @@ dependencies = [ "convert_case 0.6.0", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.87", "unicode-xid", ] +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + [[package]] name = "digest" version = "0.9.0" @@ -2586,9 +2748,9 @@ dependencies = [ [[package]] name = "discv5" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f569b8c367554666c8652305621e8bae3634a2ff5c6378081d5bd8c399c99f23" +checksum = "23e6b70634e26c909d1edbb3142b3eaf3b89da0e52f284f00ca7c80d9901ad9e" dependencies = [ "aes", "aes-gcm", @@ -2599,24 +2761,35 @@ dependencies = [ "enr 0.12.1", "fnv", "futures", - "hashlink", + "hashlink 0.9.1", "hex", "hkdf", "lazy_static", "libp2p-identity", "lru", "more-asserts", - "multiaddr 0.18.1", - "parking_lot 0.11.2", + "multiaddr 0.18.2", + "parking_lot", "rand 0.8.5", "smallvec", - "socket2 0.4.10", + "socket2", "tokio", "tracing", - "uint", + "uint 0.10.0", "zeroize", ] +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "doctest-file" version = "1.0.0" @@ -2652,9 +2825,9 @@ dependencies = [ [[package]] name = "dunce" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" [[package]] name = "dyn-clone" @@ -2662,12 +2835,6 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" -[[package]] -name = "dyn_size_of" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d4f78a40b1ec35bf8cafdaaf607ba2f773c366b0b3bda48937cacd7a8d5134" - [[package]] name = "ecdsa" version = "0.14.8" @@ -2721,9 +2888,9 @@ dependencies = [ [[package]] name = "ego-tree" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a68a4904193147e0a8dec3314640e6db742afd5f6e634f428a6af230d9b3591" +checksum = "12a0bb14ac04a9fcf170d0bbbef949b44cc492f4452bd20c095636956f653642" [[package]] name = "either" @@ -2781,19 +2948,13 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" [[package]] name = "encoding_rs" -version = "0.8.34" +version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" dependencies = [ "cfg-if", ] -[[package]] -name = "endian-type" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" - [[package]] name = "enr" version = "0.6.2" @@ -2824,7 +2985,7 @@ dependencies = [ "bytes", "ed25519-dalek", "hex", - "k256 0.13.3", + "k256 0.13.4", "log", "rand 0.8.5", "secp256k1", @@ -2835,14 +2996,14 @@ dependencies = [ [[package]] name = "enum-as-inner" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a" +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" dependencies = [ - "heck 0.4.1", + "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.87", ] [[package]] @@ -2854,18 +3015,18 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.87", ] [[package]] name = "enumn" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fd000fd6988e73bbe993ea3db9b1aa64906ab88766d654973924340c8cddb42" +checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.87", ] [[package]] @@ -2899,7 +3060,7 @@ dependencies = [ name = "eth-sparse-mpt" version = "0.1.0" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", "alloy-rlp", "alloy-trie", "criterion 0.4.0", @@ -2921,7 +3082,7 @@ dependencies = [ "serde_json", "serde_with", "smallvec", - "thiserror", + "thiserror 1.0.69", "triehash", ] @@ -2938,8 +3099,8 @@ dependencies = [ "serde", "serde_json", "sha3", - "thiserror", - "uint", + "thiserror 1.0.69", + "uint 0.9.5", ] [[package]] @@ -2976,7 +3137,7 @@ dependencies = [ "serde_yaml", "sha2 0.10.8", "ssz_rs 0.9.0 (git+https://github.com/ralexstokes/ssz-rs?rev=84ef2b71aa004f6767420badb42c902ad56b8b72)", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-stream", ] @@ -2994,30 +3155,48 @@ dependencies = [ "impl-serde", "primitive-types", "scale-info", - "uint", + "uint 0.9.5", +] + +[[package]] +name = "ethereum_serde_utils" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70cbccfccf81d67bff0ab36e591fa536c8a935b078a7b0e58c1d00d418332fc9" +dependencies = [ + "alloy-primitives 0.8.12", + "hex", + "serde", + "serde_derive", + "serde_json", ] [[package]] name = "ethereum_ssz" -version = "0.7.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e999563461faea0ab9bc0024e5e66adcee35881f3d5062f52f31a4070fe1522" +checksum = "bfbba28f4f3f32d92c06a64f5bf6c4537b5d4e21f28c689bd2bbaecfea4e0d3e" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", + "derivative", + "ethereum_serde_utils", "itertools 0.13.0", + "serde", + "serde_derive", "smallvec", + "typenum", ] [[package]] name = "ethereum_ssz_derive" -version = "0.7.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3deae99c8e74829a00ba7a92d49055732b3c1f093f2ccfa3cbc621679b6fa91" +checksum = "0d37845ba7c16bf4be8be4b5786f03a2ba5f2fda0d7f9e7cb2282f69cff420d7" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.87", ] [[package]] @@ -3033,7 +3212,7 @@ dependencies = [ "elliptic-curve 0.13.8", "ethabi", "generic-array", - "k256 0.13.3", + "k256 0.13.4", "num_enum", "open-fastrlp", "rand 0.8.5", @@ -3042,7 +3221,7 @@ dependencies = [ "serde_json", "strum", "tempfile", - "thiserror", + "thiserror 1.0.69", "tiny-keccak", "unicode-xid", ] @@ -3061,11 +3240,11 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "exponential-backoff" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47f78d87d930eee4b5686a2ab032de499c72bd1e954b84262bb03492a0f932cd" +checksum = "949eb68d436415e37b7a69c49a9900d5337616b0e420377ccc48038b86261e16" dependencies = [ - "rand 0.8.5", + "fastrand 2.2.0", ] [[package]] @@ -3101,9 +3280,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" [[package]] name = "fastrlp" @@ -3123,7 +3302,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e182f7dbc2ef73d9ef67351c5fbbea084729c48362d3ce9dd44c28e32e277fe5" dependencies = [ "libc", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -3152,6 +3331,18 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" +[[package]] +name = "filetime" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" +dependencies = [ + "cfg-if", + "libc", + "libredox", + "windows-sys 0.59.0", +] + [[package]] name = "fixed-hash" version = "0.8.0" @@ -3166,9 +3357,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.30" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" +checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" dependencies = [ "crc32fast", "miniz_oxide", @@ -3176,9 +3367,9 @@ dependencies = [ [[package]] name = "flume" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" +checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" dependencies = [ "futures-core", "futures-sink", @@ -3192,6 +3383,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" + [[package]] name = "foreign-types" version = "0.3.2" @@ -3228,6 +3425,15 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" +[[package]] +name = "fsevent-sys" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2" +dependencies = [ + "libc", +] + [[package]] name = "funty" version = "2.0.0" @@ -3246,9 +3452,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -3261,9 +3467,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -3271,15 +3477,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -3294,14 +3500,14 @@ checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" dependencies = [ "futures-core", "lock_api", - "parking_lot 0.12.3", + "parking_lot", ] [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-lite" @@ -3320,26 +3526,26 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.87", ] [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-timer" @@ -3353,9 +3559,9 @@ dependencies = [ [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -3390,6 +3596,7 @@ version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ + "serde", "typenum", "version_check", "zeroize", @@ -3401,7 +3608,7 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" dependencies = [ - "unicode-width", + "unicode-width 0.1.14", ] [[package]] @@ -3440,9 +3647,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.29.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "git2" @@ -3478,7 +3685,7 @@ dependencies = [ "pin-project", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", @@ -3499,7 +3706,7 @@ dependencies = [ "pin-project", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", @@ -3542,7 +3749,7 @@ dependencies = [ "futures-timer", "no-std-compat", "nonzero_ext", - "parking_lot 0.12.3", + "parking_lot", "portable-atomic", "quanta", "rand 0.8.5", @@ -3584,7 +3791,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.2.6", + "indexmap 2.6.0", "slab", "tokio", "tokio-util", @@ -3593,9 +3800,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab" +checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" dependencies = [ "atomic-waker", "bytes", @@ -3603,7 +3810,7 @@ dependencies = [ "futures-core", "futures-sink", "http 1.1.0", - "indexmap 2.2.6", + "indexmap 2.6.0", "slab", "tokio", "tokio-util", @@ -3653,6 +3860,17 @@ dependencies = [ "ahash", "allocator-api2", "rayon", +] + +[[package]] +name = "hashbrown" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", "serde", ] @@ -3665,6 +3883,15 @@ dependencies = [ "hashbrown 0.14.5", ] +[[package]] +name = "hashlink" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" +dependencies = [ + "hashbrown 0.14.5", +] + [[package]] name = "hdrhistogram" version = "7.5.4" @@ -3729,6 +3956,12 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + [[package]] name = "hex" version = "0.4.3" @@ -3901,9 +4134,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.9.4" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" [[package]] name = "httpdate" @@ -3935,9 +4168,9 @@ dependencies = [ [[package]] name = "hyper" -version = "0.14.30" +version = "0.14.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" +checksum = "8c08302e8fa335b151b788c775ff56e7a03ae64ff85c548ee820fecb70356e85" dependencies = [ "bytes", "futures-channel", @@ -3950,7 +4183,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.5.7", + "socket2", "tokio", "tower-service", "tracing", @@ -3959,14 +4192,14 @@ dependencies = [ [[package]] name = "hyper" -version = "1.4.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a" dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.5", + "h2 0.4.6", "http 1.1.0", "http-body 1.0.1", "httparse", @@ -3986,7 +4219,7 @@ checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", "http 0.2.12", - "hyper 0.14.30", + "hyper 0.14.31", "log", "rustls 0.21.12", "rustls-native-certs 0.6.3", @@ -3996,22 +4229,22 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.2" +version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" +checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" dependencies = [ "futures-util", "http 1.1.0", - "hyper 1.4.1", + "hyper 1.5.0", "hyper-util", "log", - "rustls 0.23.12", - "rustls-native-certs 0.7.1", + "rustls 0.23.16", + "rustls-native-certs 0.8.0", "rustls-pki-types", "tokio", "tokio-rustls 0.26.0", "tower-service", - "webpki-roots 0.26.3", + "webpki-roots 0.26.6", ] [[package]] @@ -4021,7 +4254,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ "bytes", - "hyper 0.14.30", + "hyper 0.14.31", "native-tls", "tokio", "tokio-native-tls", @@ -4035,7 +4268,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper 1.4.1", + "hyper 1.5.0", "hyper-util", "native-tls", "tokio", @@ -4045,29 +4278,28 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.6" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ab92f4f49ee4fb4f997c784b7a2e0fa70050211e0b6a287f898c3c9785ca956" +checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" dependencies = [ "bytes", "futures-channel", "futures-util", "http 1.1.0", "http-body 1.0.1", - "hyper 1.4.1", + "hyper 1.5.0", "pin-project-lite", - "socket2 0.5.7", + "socket2", "tokio", - "tower", "tower-service", "tracing", ] [[package]] name = "iana-time-zone" -version = "0.1.60" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -4086,6 +4318,124 @@ dependencies = [ "cc", ] +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -4104,12 +4454,33 @@ dependencies = [ [[package]] name = "idna" -version = "0.5.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "if-addrs" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a78a89907582615b19f6f0da1af18abf6ff08be259395669b834b057a7ee92d8" +dependencies = [ + "libc", + "windows-sys 0.52.0", ] [[package]] @@ -4188,34 +4559,61 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.6" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ + "arbitrary", "equivalent", - "hashbrown 0.14.5", + "hashbrown 0.15.1", "serde", ] [[package]] name = "indicatif" -version = "0.17.8" +version = "0.17.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3" +checksum = "cbf675b85ed934d3c67b5c5469701eec7db22689d0a2139d856e0925fa28b281" dependencies = [ "console", - "instant", "number_prefix", "portable-atomic", - "unicode-width", + "unicode-width 0.2.0", + "web-time", ] +[[package]] +name = "indoc" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5" + [[package]] name = "infer" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64e9829a50b42bb782c1df523f78d332fe371b10c661e78b7a3c34b0198e9fac" +[[package]] +name = "inotify" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff" +dependencies = [ + "bitflags 1.3.2", + "inotify-sys", + "libc", +] + +[[package]] +name = "inotify-sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" +dependencies = [ + "libc", +] + [[package]] name = "inout" version = "0.1.3" @@ -4226,6 +4624,20 @@ dependencies = [ "generic-array", ] +[[package]] +name = "instability" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b829f37dead9dc39df40c2d3376c179fdfd2ac771f53f55d3c30dc096a3c0c6e" +dependencies = [ + "darling", + "indoc", + "pretty_assertions", + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "instant" version = "0.1.13" @@ -4237,9 +4649,9 @@ dependencies = [ [[package]] name = "integer-encoding" -version = "4.0.0" +version = "4.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "924df4f0e24e2e7f9cdd90babb0b96f93b20f3ecfa949ea9e6613756b8c8e1bf" +checksum = "0d762194228a2f1c11063e46e32e5acb96e66e906382b9eb5441f2e0504bbd5a" [[package]] name = "integer-sqrt" @@ -4265,13 +4677,22 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "intrusive-collections" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "189d0897e4cbe8c75efedf3502c18c887b05046e59d28404d4d8e46cbc4d1e86" +dependencies = [ + "memoffset", +] + [[package]] name = "ipconfig" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" dependencies = [ - "socket2 0.5.7", + "socket2", "widestring", "windows-sys 0.48.0", "winreg", @@ -4279,15 +4700,15 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.9.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" [[package]] name = "iri-string" -version = "0.7.2" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f5f6c2df22c009ac44f6f1499308e7a3ac7ba42cd2378475cc691510e1eef1b" +checksum = "dc0f0a572e8ffe56e2ff4f769f32ffe919282c3916799f8b68688b6030063bea" dependencies = [ "memchr", "serde", @@ -4295,20 +4716,20 @@ dependencies = [ [[package]] name = "is-terminal" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" +checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" dependencies = [ - "hermit-abi 0.3.9", + "hermit-abi 0.4.0", "libc", "windows-sys 0.52.0", ] [[package]] name = "is_terminal_polyfill" -version = "1.70.0" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itertools" @@ -4353,7 +4774,7 @@ dependencies = [ "combine", "jni-sys", "log", - "thiserror", + "thiserror 1.0.69", "walkdir", ] @@ -4374,64 +4795,64 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" dependencies = [ "wasm-bindgen", ] [[package]] name = "jsonrpsee" -version = "0.20.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "affdc52f7596ccb2d7645231fc6163bb314630c989b64998f3699a28b4d5d4dc" -dependencies = [ - "jsonrpsee-client-transport 0.20.3", - "jsonrpsee-core 0.20.3", - "jsonrpsee-http-client 0.20.3", - "jsonrpsee-proc-macros 0.20.3", - "jsonrpsee-server 0.20.3", - "jsonrpsee-types 0.20.3", - "jsonrpsee-wasm-client 0.20.3", - "jsonrpsee-ws-client 0.20.3", +version = "0.20.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138572befc78a9793240645926f30161f8b4143d2be18d09e44ed9814bd7ee2c" +dependencies = [ + "jsonrpsee-client-transport 0.20.4", + "jsonrpsee-core 0.20.4", + "jsonrpsee-http-client 0.20.4", + "jsonrpsee-proc-macros 0.20.4", + "jsonrpsee-server 0.20.4", + "jsonrpsee-types 0.20.4", + "jsonrpsee-wasm-client 0.20.4", + "jsonrpsee-ws-client 0.20.4", "tokio", "tracing", ] [[package]] name = "jsonrpsee" -version = "0.24.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd1ead9fb95614e8dc5556d12a8681c2f6d352d0c1d3efc8708c7ccbba47bc6" -dependencies = [ - "jsonrpsee-client-transport 0.24.4", - "jsonrpsee-core 0.24.4", - "jsonrpsee-http-client 0.24.4", - "jsonrpsee-proc-macros 0.24.4", - "jsonrpsee-server 0.24.4", - "jsonrpsee-types 0.24.4", - "jsonrpsee-wasm-client 0.24.4", - "jsonrpsee-ws-client 0.24.4", +version = "0.24.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5c71d8c1a731cc4227c2f698d377e7848ca12c8a48866fc5e6951c43a4db843" +dependencies = [ + "jsonrpsee-client-transport 0.24.7", + "jsonrpsee-core 0.24.7", + "jsonrpsee-http-client 0.24.7", + "jsonrpsee-proc-macros 0.24.7", + "jsonrpsee-server 0.24.7", + "jsonrpsee-types 0.24.7", + "jsonrpsee-wasm-client 0.24.7", + "jsonrpsee-ws-client 0.24.7", "tokio", "tracing", ] [[package]] name = "jsonrpsee-client-transport" -version = "0.20.3" +version = "0.20.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b005c793122d03217da09af68ba9383363caa950b90d3436106df8cabce935" +checksum = "5c671353e4adf926799107bd7f5724a06b6bc0a333db442a0843c58640bdd0c1" dependencies = [ "futures-channel", "futures-util", "gloo-net 0.4.0", "http 0.2.12", - "jsonrpsee-core 0.20.3", + "jsonrpsee-core 0.20.4", "pin-project", "rustls-native-certs 0.6.3", "soketto 0.7.1", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-rustls 0.24.1", "tokio-util", @@ -4442,22 +4863,22 @@ dependencies = [ [[package]] name = "jsonrpsee-client-transport" -version = "0.24.4" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89841d4f03a14c055eb41d4f41901819573ef948e8ee0d5c86466fd286b2ce7f" +checksum = "548125b159ba1314104f5bb5f38519e03a41862786aa3925cf349aae9cdd546e" dependencies = [ "base64 0.22.1", "futures-channel", "futures-util", "gloo-net 0.6.0", "http 1.1.0", - "jsonrpsee-core 0.24.4", + "jsonrpsee-core 0.24.7", "pin-project", - "rustls 0.23.12", + "rustls 0.23.16", "rustls-pki-types", "rustls-platform-verifier", "soketto 0.8.0", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-rustls 0.26.0", "tokio-util", @@ -4467,9 +4888,9 @@ dependencies = [ [[package]] name = "jsonrpsee-core" -version = "0.20.3" +version = "0.20.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da2327ba8df2fdbd5e897e2b5ed25ce7f299d345b9736b6828814c3dbd1fd47b" +checksum = "f24ea59b037b6b9b0e2ebe2c30a3e782b56bd7c76dcc5d6d70ba55d442af56e3" dependencies = [ "anyhow", "async-lock", @@ -4477,15 +4898,15 @@ dependencies = [ "beef", "futures-timer", "futures-util", - "hyper 0.14.30", - "jsonrpsee-types 0.20.3", - "parking_lot 0.12.3", + "hyper 0.14.31", + "jsonrpsee-types 0.20.4", + "parking_lot", "rand 0.8.5", "rustc-hash 1.1.0", "serde", "serde_json", "soketto 0.7.1", - "thiserror", + "thiserror 1.0.69", "tokio", "tracing", "wasm-bindgen-futures", @@ -4493,9 +4914,9 @@ dependencies = [ [[package]] name = "jsonrpsee-core" -version = "0.24.4" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff79651479f69ada7bda604ef2acf3f1aa50755d97cc36d25ff04c2664f9d96f" +checksum = "f2882f6f8acb9fdaec7cefc4fd607119a9bd709831df7d7672a1d3b644628280" dependencies = [ "async-trait", "bytes", @@ -4504,14 +4925,14 @@ dependencies = [ "http 1.1.0", "http-body 1.0.1", "http-body-util", - "jsonrpsee-types 0.24.4", - "parking_lot 0.12.3", + "jsonrpsee-types 0.24.7", + "parking_lot", "pin-project", "rand 0.8.5", "rustc-hash 2.0.0", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-stream", "tracing", @@ -4520,54 +4941,54 @@ dependencies = [ [[package]] name = "jsonrpsee-http-client" -version = "0.20.3" +version = "0.20.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f80c17f62c7653ce767e3d7288b793dfec920f97067ceb189ebdd3570f2bc20" +checksum = "57c7b9f95208927653e7965a98525e7fc641781cab89f0e27c43fa2974405683" dependencies = [ "async-trait", - "hyper 0.14.30", + "hyper 0.14.31", "hyper-rustls 0.24.2", - "jsonrpsee-core 0.20.3", - "jsonrpsee-types 0.20.3", + "jsonrpsee-core 0.20.4", + "jsonrpsee-types 0.20.4", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "tokio", - "tower", + "tower 0.4.13", "tracing", "url", ] [[package]] name = "jsonrpsee-http-client" -version = "0.24.4" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ed8b301b19f4dad8ddc66ed956a70fc227def5c19b3898e0a29ce8f0edee06" +checksum = "b3638bc4617f96675973253b3a45006933bde93c2fd8a6170b33c777cc389e5b" dependencies = [ "async-trait", "base64 0.22.1", "http-body 1.0.1", - "hyper 1.4.1", - "hyper-rustls 0.27.2", + "hyper 1.5.0", + "hyper-rustls 0.27.3", "hyper-util", - "jsonrpsee-core 0.24.4", - "jsonrpsee-types 0.24.4", - "rustls 0.23.12", + "jsonrpsee-core 0.24.7", + "jsonrpsee-types 0.24.7", + "rustls 0.23.16", "rustls-platform-verifier", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "tokio", - "tower", + "tower 0.4.13", "tracing", "url", ] [[package]] name = "jsonrpsee-proc-macros" -version = "0.20.3" +version = "0.20.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29110019693a4fa2dbda04876499d098fa16d70eba06b1e6e2b3f1b251419515" +checksum = "dcc0eba68ba205452bcb4c7b80a79ddcb3bf36c261a841b239433142db632d24" dependencies = [ "heck 0.4.1", "proc-macro-crate 1.1.3", @@ -4578,138 +4999,138 @@ dependencies = [ [[package]] name = "jsonrpsee-proc-macros" -version = "0.24.4" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0d4c6bec4909c966f59f52db3655c0e9d4685faae8b49185973d9d7389bb884" +checksum = "c06c01ae0007548e73412c08e2285ffe5d723195bf268bce67b1b77c3bb2a14d" dependencies = [ "heck 0.5.0", - "proc-macro-crate 3.1.0", + "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.87", ] [[package]] name = "jsonrpsee-server" -version = "0.20.3" +version = "0.20.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82c39a00449c9ef3f50b84fc00fc4acba20ef8f559f07902244abf4c15c5ab9c" +checksum = "a482bc4e25eebd0adb61a3468c722763c381225bd3ec46e926f709df8a8eb548" dependencies = [ "futures-util", "http 0.2.12", - "hyper 0.14.30", - "jsonrpsee-core 0.20.3", - "jsonrpsee-types 0.20.3", + "hyper 0.14.31", + "jsonrpsee-core 0.20.4", + "jsonrpsee-types 0.20.4", "route-recognizer", "serde", "serde_json", "soketto 0.7.1", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-stream", "tokio-util", - "tower", + "tower 0.4.13", "tracing", ] [[package]] name = "jsonrpsee-server" -version = "0.24.4" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebe2198e5fd96cf2153ecc123364f699b6e2151317ea09c7bf799c43c2fe1415" +checksum = "82ad8ddc14be1d4290cd68046e7d1d37acd408efed6d3ca08aefcc3ad6da069c" dependencies = [ "futures-util", "http 1.1.0", "http-body 1.0.1", "http-body-util", - "hyper 1.4.1", + "hyper 1.5.0", "hyper-util", - "jsonrpsee-core 0.24.4", - "jsonrpsee-types 0.24.4", + "jsonrpsee-core 0.24.7", + "jsonrpsee-types 0.24.7", "pin-project", "route-recognizer", "serde", "serde_json", "soketto 0.8.0", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-stream", "tokio-util", - "tower", + "tower 0.4.13", "tracing", ] [[package]] name = "jsonrpsee-types" -version = "0.20.3" +version = "0.20.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be0be325642e850ed0bdff426674d2e66b2b7117c9be23a7caef68a2902b7d9" +checksum = "3264e339143fe37ed081953842ee67bfafa99e3b91559bdded6e4abd8fc8535e" dependencies = [ "anyhow", "beef", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "tracing", ] [[package]] name = "jsonrpsee-types" -version = "0.24.4" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "531e386460425e49679587871a056f2895a47dade21457324ad1262cd78ef6d9" +checksum = "a178c60086f24cc35bb82f57c651d0d25d99c4742b4d335de04e97fa1f08a8a1" dependencies = [ "http 1.1.0", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "jsonrpsee-wasm-client" -version = "0.20.3" +version = "0.20.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c7cbb3447cf14fd4d2f407c3cc96e6c9634d5440aa1fbed868a31f3c02b27f0" +checksum = "9437dd0e8728897d0aa5a0075b8710266300e55ced07101ca0930fac4a611384" dependencies = [ - "jsonrpsee-client-transport 0.20.3", - "jsonrpsee-core 0.20.3", - "jsonrpsee-types 0.20.3", + "jsonrpsee-client-transport 0.20.4", + "jsonrpsee-core 0.20.4", + "jsonrpsee-types 0.20.4", ] [[package]] name = "jsonrpsee-wasm-client" -version = "0.24.4" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a2d2206c8f04c6b79a11bd1d92d6726b6f7fd3dec57c91e07fa53e867268bbb" +checksum = "1a01cd500915d24ab28ca17527e23901ef1be6d659a2322451e1045532516c25" dependencies = [ - "jsonrpsee-client-transport 0.24.4", - "jsonrpsee-core 0.24.4", - "jsonrpsee-types 0.24.4", + "jsonrpsee-client-transport 0.24.7", + "jsonrpsee-core 0.24.7", + "jsonrpsee-types 0.24.7", ] [[package]] name = "jsonrpsee-ws-client" -version = "0.20.3" +version = "0.20.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bca9cb3933ccae417eb6b08c3448eb1cb46e39834e5b503e395e5e5bd08546c0" +checksum = "6d06eeabbb55f0af8405288390a358ebcceb6e79e1390741e6f152309c4d6076" dependencies = [ "http 0.2.12", - "jsonrpsee-client-transport 0.20.3", - "jsonrpsee-core 0.20.3", - "jsonrpsee-types 0.20.3", + "jsonrpsee-client-transport 0.20.4", + "jsonrpsee-core 0.20.4", + "jsonrpsee-types 0.20.4", "url", ] [[package]] name = "jsonrpsee-ws-client" -version = "0.24.4" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87bc869e143d430e748988261d19b630e8f1692074e68f1a7f0eb4c521d2fc58" +checksum = "0fe322e0896d0955a3ebdd5bf813571c53fea29edd713bc315b76620b327e86d" dependencies = [ "http 1.1.0", - "jsonrpsee-client-transport 0.24.4", - "jsonrpsee-core 0.24.4", - "jsonrpsee-types 0.24.4", + "jsonrpsee-client-transport 0.24.7", + "jsonrpsee-core 0.24.7", + "jsonrpsee-types 0.24.7", "url", ] @@ -4742,9 +5163,9 @@ dependencies = [ [[package]] name = "k256" -version = "0.13.3" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" dependencies = [ "cfg-if", "ecdsa 0.16.9", @@ -4765,9 +5186,9 @@ dependencies = [ [[package]] name = "keccak-asm" -version = "0.1.1" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47a3633291834c4fbebf8673acbc1b04ec9d151418ff9b8e26dcd79129928758" +checksum = "505d1856a39b200489082f90d897c3f07c455563880bc5952e38eabf731c83b6" dependencies = [ "digest 0.10.7", "sha3-asm", @@ -4788,6 +5209,26 @@ version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4933f3f57a8e9d9da04db23fb153356ecaf00cbd14aee46279c33dc80925c37" +[[package]] +name = "kqueue" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7447f1ca1b7b563588a205fe93dea8df60fd981423a768bc1c0ded35ed147d0c" +dependencies = [ + "kqueue-sys", + "libc", +] + +[[package]] +name = "kqueue-sys" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b" +dependencies = [ + "bitflags 1.3.2", + "libc", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -4797,12 +5238,6 @@ dependencies = [ "spin", ] -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - [[package]] name = "lexical" version = "6.1.1" @@ -4878,9 +5313,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.161" +version = "0.2.162" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" +checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398" [[package]] name = "libgit2-sys" @@ -4906,9 +5341,9 @@ dependencies = [ [[package]] name = "libm" -version = "0.2.8" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" [[package]] name = "libp2p-identity" @@ -4921,19 +5356,19 @@ dependencies = [ "ed25519-dalek", "hkdf", "libsecp256k1", - "multihash 0.19.1", + "multihash 0.19.2", "quick-protobuf", "sha2 0.10.8", - "thiserror", + "thiserror 1.0.69", "tracing", "zeroize", ] [[package]] name = "libproc" -version = "0.14.8" +version = "0.14.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae9ea4b75e1a81675429dafe43441df1caea70081e82246a8cccf514884a88bb" +checksum = "e78a09b56be5adbcad5aa1197371688dc6bb249a26da3bca2011ee2fb987ebfb" dependencies = [ "bindgen", "errno", @@ -4948,6 +5383,7 @@ checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ "bitflags 2.6.0", "libc", + "redox_syscall", ] [[package]] @@ -5011,9 +5447,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.18" +version = "1.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c15da26e5af7e25c90b37a2d75cdbf940cf4a55316de9d84c679c9b8bfabf82e" +checksum = "d2d16453e800a8cf6dd2fc3eb4bc99b786a9b90c663b8559a5b1a041bf89e472" dependencies = [ "cc", "libc", @@ -5034,6 +5470,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47186c6da4d81ca383c7c47c1bfc80f4b95f4720514d860a5407aaf4233f9588" dependencies = [ "linked-hash-map", + "serde", ] [[package]] @@ -5042,6 +5479,12 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +[[package]] +name = "litemap" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" + [[package]] name = "lock_api" version = "0.4.12" @@ -5050,6 +5493,7 @@ checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", + "serde", ] [[package]] @@ -5060,11 +5504,11 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "lru" -version = "0.12.3" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc" +checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" dependencies = [ - "hashbrown 0.14.5", + "hashbrown 0.15.1", ] [[package]] @@ -5078,19 +5522,18 @@ dependencies = [ [[package]] name = "lz4" -version = "1.26.0" +version = "1.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "958b4caa893816eea05507c20cfe47574a43d9a697138a7872990bba8a0ece68" +checksum = "4d1febb2b4a79ddd1980eede06a8f7902197960aa0383ffcfdd62fe723036725" dependencies = [ - "libc", "lz4-sys", ] [[package]] name = "lz4-sys" -version = "1.10.0" +version = "1.11.1+lz4-1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "109de74d5d2353660401699a4174a4ff23fcc649caf553df71933c7fb45ad868" +checksum = "6bd8c0d6c6ed0cd30b3652886bb8711dc4bb01d637a68105a3d5158039b418e6" dependencies = [ "cc", "libc", @@ -5176,13 +5619,22 @@ dependencies = [ [[package]] name = "memmap2" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" +checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" dependencies = [ "libc", ] +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + [[package]] name = "mempool-dumpster" version = "0.1.1" @@ -5190,14 +5642,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b453bd8e35ec92138b093172731fe7920cdf397f2a709e789243147a79772b9d" dependencies = [ "chrono", - "clap 4.5.19", + "clap 4.5.21", "csv", "eyre", "indicatif", "polars", "scraper", "serde", - "thiserror", + "thiserror 1.0.69", "tracing", "tracing-subscriber", "ureq", @@ -5206,59 +5658,67 @@ dependencies = [ [[package]] name = "metrics" -version = "0.23.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "884adb57038347dfbaf2d5065887b6cf4312330dc8e94bc30a1a839bd79d3261" +checksum = "8ae428771d17306715c5091d446327d1cfdedc82185c65ba8423ab404e45bf10" dependencies = [ "ahash", "portable-atomic", ] +[[package]] +name = "metrics-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3dbdd96ed57d565ec744cba02862d707acf373c5772d152abae6ec5c4e24f6c" +dependencies = [ + "proc-macro2", + "quote", + "regex", + "syn 2.0.87", +] + [[package]] name = "metrics-exporter-prometheus" -version = "0.15.3" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4f0c8427b39666bf970460908b213ec09b3b350f20c0c2eabcbba51704a08e6" +checksum = "85b6f8152da6d7892ff1b7a1c0fa3f435e92b5918ad67035c3bb432111d9a29b" dependencies = [ "base64 0.22.1", - "indexmap 2.2.6", + "indexmap 2.6.0", "metrics", "metrics-util", "quanta", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "metrics-process" -version = "2.1.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb524e5438255eaa8aa74214d5a62713b77b2c3c6e3c0bbeee65cfd9a58948ba" +checksum = "57ca8ecd85575fbb143b2678cb123bb818779391ec0f745b1c4a9dbabadde407" dependencies = [ + "libc", "libproc", "mach2", "metrics", "once_cell", - "procfs", + "procfs 0.17.0", "rlimit", - "windows 0.57.0", + "windows 0.58.0", ] [[package]] name = "metrics-util" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4259040465c955f9f2f1a4a8a16dc46726169bca0f88e8fb2dbeced487c3e828" +checksum = "15b482df36c13dd1869d73d14d28cd4855fbd6cfc32294bee109908a9f4a4ed7" dependencies = [ - "aho-corasick", "crossbeam-epoch", "crossbeam-utils", - "hashbrown 0.14.5", - "indexmap 2.2.6", + "hashbrown 0.15.1", "metrics", - "num_cpus", - "ordered-float", "quanta", - "radix_trie", "sketches-ddsketch", ] @@ -5268,7 +5728,7 @@ version = "0.1.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.87", ] [[package]] @@ -5285,7 +5745,7 @@ dependencies = [ "reqwest 0.11.27", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "tokio", "tracing", ] @@ -5314,11 +5774,11 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.4" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" dependencies = [ - "adler", + "adler2", ] [[package]] @@ -5335,12 +5795,13 @@ dependencies = [ [[package]] name = "mio" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ "hermit-abi 0.3.9", "libc", + "log", "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.52.0", ] @@ -5369,7 +5830,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.87", ] [[package]] @@ -5431,26 +5892,26 @@ dependencies = [ "percent-encoding", "serde", "static_assertions", - "unsigned-varint", + "unsigned-varint 0.7.2", "url", ] [[package]] name = "multiaddr" -version = "0.18.1" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b852bc02a2da5feed68cd14fa50d0774b92790a5bdbfa932a813926c8472070" +checksum = "fe6351f60b488e04c1d21bc69e56b89cb3f5e8f5d22557d6e8031bdfd79b6961" dependencies = [ "arrayref", "byteorder", "data-encoding", "libp2p-identity", "multibase", - "multihash 0.19.1", + "multihash 0.19.2", "percent-encoding", "serde", "static_assertions", - "unsigned-varint", + "unsigned-varint 0.8.0", "url", ] @@ -5475,17 +5936,17 @@ dependencies = [ "digest 0.10.7", "multihash-derive", "sha2 0.10.8", - "unsigned-varint", + "unsigned-varint 0.7.2", ] [[package]] name = "multihash" -version = "0.19.1" +version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "076d548d76a0e2a0d4ab471d0b1c36c577786dfc4471242035d97a12a735c492" +checksum = "cc41f430805af9d1cf4adae4ed2149c759b877b01d909a1f40256188d09345d2" dependencies = [ "core2", - "unsigned-varint", + "unsigned-varint 0.8.0", ] [[package]] @@ -5499,7 +5960,7 @@ dependencies = [ "proc-macro2", "quote", "syn 1.0.109", - "synstructure", + "synstructure 0.12.6", ] [[package]] @@ -5556,15 +6017,6 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" -[[package]] -name = "nibble_vec" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" -dependencies = [ - "smallvec", -] - [[package]] name = "no-std-compat" version = "0.4.1" @@ -5587,6 +6039,25 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38bf9645c8b145698bb0b18a4637dcacbc421ea49bef2317e4fd8065a387cf21" +[[package]] +name = "notify" +version = "6.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d" +dependencies = [ + "bitflags 2.6.0", + "filetime", + "fsevent-sys", + "inotify", + "kqueue", + "libc", + "log", + "mio 0.8.11", + "serde", + "walkdir", + "windows-sys 0.48.0", +] + [[package]] name = "now" version = "0.1.3" @@ -5637,6 +6108,7 @@ checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", "num-traits", + "serde", ] [[package]] @@ -5724,23 +6196,23 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" dependencies = [ "num_enum_derive", ] [[package]] name = "num_enum_derive" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ - "proc-macro-crate 3.1.0", + "proc-macro-crate 1.1.3", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.87", ] [[package]] @@ -5774,18 +6246,22 @@ dependencies = [ [[package]] name = "object" -version = "0.36.2" +version = "0.36.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +dependencies = [ + "critical-section", + "portable-atomic", +] [[package]] name = "oorandom" @@ -5795,45 +6271,83 @@ checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" [[package]] name = "op-alloy-consensus" -version = "0.2.7" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3041068147bb9abce8973644991e11c075fa8a7931a272bc8eb935971a2d03d7" +checksum = "f26c3b35b7b3e36d15e0563eebffe13c1d9ca16b7aaffcb6a64354633547e16b" dependencies = [ "alloy-consensus", "alloy-eips", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", "alloy-rlp", "alloy-serde", + "arbitrary", "derive_more 1.0.0", "serde", + "serde_with", "spin", ] [[package]] -name = "op-alloy-network" -version = "0.2.2" +name = "op-alloy-genesis" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66184e6c92269ba4ef1f80e8566ce11d41b584884ce7476d4b1b5e0e38503ecb" +checksum = "ccacc2efed3d60d98ea581bddb885df1c6c62a592e55de049cfefd94116112cd" dependencies = [ "alloy-consensus", "alloy-eips", + "alloy-primitives 0.8.12", + "alloy-sol-types", + "serde", + "serde_repr", +] + +[[package]] +name = "op-alloy-network" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ff6fc0f94702ea0f4d8466bffdc990067ae6df9213465df9b7957f74f1e5461" +dependencies = [ + "alloy-consensus", "alloy-network", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", "alloy-rpc-types-eth", "op-alloy-consensus", "op-alloy-rpc-types", ] +[[package]] +name = "op-alloy-protocol" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5f8e6ec6b91c6aaeb20860b455a52fd8e300acfe5d534e96e9073a24f853e74" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives 0.8.12", + "alloy-rlp", + "alloy-serde", + "async-trait", + "derive_more 1.0.0", + "op-alloy-consensus", + "op-alloy-genesis", + "serde", + "tracing", + "unsigned-varint 0.8.0", +] + [[package]] name = "op-alloy-rpc-types" -version = "0.2.2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9c604cd3b9680d0edd0b7127f3550bcff634c2d2efe27b2b4853e72320186a8" +checksum = "94bae9bf91b620e1e2c2291562e5998bc1247bd8ada011773e1997b31a95de99" dependencies = [ - "alloy-network", - "alloy-primitives 0.8.0", + "alloy-consensus", + "alloy-eips", + "alloy-network-primitives", + "alloy-primitives 0.8.12", "alloy-rpc-types-eth", "alloy-serde", + "arbitrary", "op-alloy-consensus", "serde", "serde_json", @@ -5841,14 +6355,18 @@ dependencies = [ [[package]] name = "op-alloy-rpc-types-engine" -version = "0.2.7" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ea246be3da604d2f68e86cc510cf05219db0ed24273ebd59d86065971ba0e3f" +checksum = "4b52ee59c86537cff83e8c7f2a6aa287a94f3608bb40c06d442aafd0c2e807a4" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", "alloy-rpc-types-engine", "alloy-serde", + "derive_more 1.0.0", + "ethereum_ssz", + "op-alloy-protocol", "serde", + "snap", ] [[package]] @@ -5857,14 +6375,14 @@ version = "0.1.0" dependencies = [ "async-trait", "clap_builder", - "jsonrpsee 0.24.4", + "jsonrpsee 0.24.7", "op-rbuilder-node-optimism", "rbuilder", "reth", "reth-cli-util", "reth-discv4", - "reth-node-optimism", - "reth-optimism-rpc", + "reth-optimism-cli", + "reth-optimism-node", "tikv-jemallocator", "tokio", "tracing", @@ -5875,21 +6393,23 @@ dependencies = [ name = "op-rbuilder-node-optimism" version = "0.0.0" dependencies = [ - "clap 4.5.19", + "clap 4.5.21", "eyre", "op-rbuilder-payload-builder", "rbuilder-bundle-pool-operations", "reth-basic-payload-builder", - "reth-chainspec", "reth-evm", - "reth-evm-optimism", + "reth-node-api", "reth-node-builder", - "reth-node-optimism", + "reth-optimism-chainspec", + "reth-optimism-evm", + "reth-optimism-node", "reth-payload-builder", "reth-primitives", "reth-provider", "reth-tracing", "reth-transaction-pool", + "reth-trie-db", "tracing", "transaction-pool-bundle-ext", ] @@ -5898,19 +6418,27 @@ dependencies = [ name = "op-rbuilder-payload-builder" version = "0.1.0" dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-rpc-types-beacon", + "alloy-rpc-types-engine", + "op-alloy-consensus", "reth-basic-payload-builder", "reth-chain-state", "reth-chainspec", "reth-evm", - "reth-evm-optimism", "reth-execution-types", - "reth-node-optimism", + "reth-optimism-chainspec", + "reth-optimism-consensus", + "reth-optimism-evm", + "reth-optimism-forks", + "reth-optimism-node", "reth-optimism-payload-builder", "reth-payload-builder", + "reth-payload-primitives", "reth-primitives", "reth-provider", "reth-revm", - "reth-rpc-types", "reth-trie", "revm", "tracing", @@ -5950,9 +6478,9 @@ dependencies = [ [[package]] name = "openssl" -version = "0.10.66" +version = "0.10.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" +checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" dependencies = [ "bitflags 2.6.0", "cfg-if", @@ -5971,7 +6499,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.87", ] [[package]] @@ -5982,9 +6510,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.103" +version = "0.9.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" +checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" dependencies = [ "cc", "libc", @@ -5998,15 +6526,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" -[[package]] -name = "ordered-float" -version = "4.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ff2cf528c6c03d9ed653d6c4ce1dc0582dc4af309790ad92f07c1cd551b0be" -dependencies = [ - "num-traits", -] - [[package]] name = "os_str_bytes" version = "6.6.1" @@ -6047,6 +6566,7 @@ version = "3.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" dependencies = [ + "arbitrary", "arrayvec", "bitvec", "byte-slice-cast", @@ -6062,7 +6582,7 @@ version = "3.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" dependencies = [ - "proc-macro-crate 3.1.0", + "proc-macro-crate 3.2.0", "proc-macro2", "quote", "syn 1.0.109", @@ -6070,20 +6590,9 @@ dependencies = [ [[package]] name = "parking" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" - -[[package]] -name = "parking_lot" -version = "0.11.2" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core 0.8.6", -] +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" @@ -6092,21 +6601,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", - "parking_lot_core 0.9.10", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" -dependencies = [ - "cfg-if", - "instant", - "libc", - "redox_syscall 0.2.16", - "smallvec", - "winapi", + "parking_lot_core", ] [[package]] @@ -6117,7 +6612,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.3", + "redox_syscall", "smallvec", "windows-targets 0.52.6", ] @@ -6206,28 +6701,15 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.11" +version = "2.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd53dff83f26735fdc1ca837098ccf133605d794cdae66acfc2bfac3ec809d95" +checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442" dependencies = [ "memchr", - "thiserror", + "thiserror 1.0.69", "ucd-trie", ] -[[package]] -name = "ph" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b7b74d575d7c11fb653fae69688be5206cafc1ead33c01ce61ac7f36eae45b" -dependencies = [ - "binout", - "bitm", - "dyn_size_of", - "rayon", - "wyhash", -] - [[package]] name = "pharos" version = "0.5.3" @@ -6235,7 +6717,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" dependencies = [ "futures", - "rustc_version 0.4.0", + "rustc_version 0.4.1", ] [[package]] @@ -6244,7 +6726,9 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" dependencies = [ + "phf_macros 0.10.0", "phf_shared 0.10.0", + "proc-macro-hack", ] [[package]] @@ -6253,7 +6737,7 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" dependencies = [ - "phf_macros", + "phf_macros 0.11.2", "phf_shared 0.11.2", ] @@ -6287,6 +6771,20 @@ dependencies = [ "rand 0.8.5", ] +[[package]] +name = "phf_macros" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58fdf3184dd560f160dd73922bea2d5cd6e8f064bf4b13110abd81b03697b4e0" +dependencies = [ + "phf_generator 0.10.0", + "phf_shared 0.10.0", + "proc-macro-hack", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "phf_macros" version = "0.11.2" @@ -6297,7 +6795,7 @@ dependencies = [ "phf_shared 0.11.2", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.87", ] [[package]] @@ -6320,29 +6818,29 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.5" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.5" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.87", ] [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" [[package]] name = "pin-utils" @@ -6383,9 +6881,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "plain_hasher" @@ -6407,9 +6905,9 @@ dependencies = [ [[package]] name = "plotters" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15b6eccb8484002195a3e44fe65a4ce8e93a625797a063735536fd59cb01cf3" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" dependencies = [ "num-traits", "plotters-backend", @@ -6420,15 +6918,15 @@ dependencies = [ [[package]] name = "plotters-backend" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "414cec62c6634ae900ea1c56128dfe87cf63e7caece0852ec76aba307cebadb7" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" [[package]] name = "plotters-svg" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81b30686a7d9c3e010b84284bdd26a29f2138574f52f5eb6f794fc0ad924e705" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" dependencies = [ "plotters-backend", ] @@ -6460,7 +6958,7 @@ dependencies = [ "multiversion", "num-traits", "polars-error", - "thiserror", + "thiserror 1.0.69", "version_check", ] @@ -6477,7 +6975,7 @@ dependencies = [ "comfy-table", "either", "hashbrown 0.14.5", - "indexmap 2.2.6", + "indexmap 2.6.0", "num-traits", "once_cell", "polars-arrow", @@ -6489,7 +6987,7 @@ dependencies = [ "rayon", "regex", "smartstring", - "thiserror", + "thiserror 1.0.69", "version_check", "xxhash-rust", ] @@ -6502,7 +7000,7 @@ checksum = "40d09c3a7337e53b38c37b57999038440fa39c6801b9ba48afaecd8e16f7ac0a" dependencies = [ "arrow2", "regex", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -6568,7 +7066,7 @@ dependencies = [ "argminmax", "arrow2", "either", - "indexmap 2.2.6", + "indexmap 2.6.0", "memchr", "polars-arrow", "polars-core", @@ -6682,6 +7180,12 @@ dependencies = [ "version_check", ] +[[package]] +name = "pollster" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22686f4785f02a4fcc856d3b3bb19bf6c8160d103f7a99cc258bddd0251dc7f2" + [[package]] name = "polyval" version = "0.6.2" @@ -6696,9 +7200,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.7.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265" +checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" [[package]] name = "powerfmt" @@ -6708,9 +7212,12 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] [[package]] name = "precomputed-hash" @@ -6720,9 +7227,9 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "predicates" -version = "3.1.0" +version = "3.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b87bfd4605926cdfefc1c3b5f8fe560e3feca9d5552cf68c466d3d8236c7e8" +checksum = "7e9086cc7640c29a356d1a29fd134380bee9d8f79a17410aa76e7ad295f42c97" dependencies = [ "anstyle", "predicates-core", @@ -6730,20 +7237,30 @@ dependencies = [ [[package]] name = "predicates-core" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174" +checksum = "ae8177bee8e75d6846599c6b9ff679ed51e882816914eec639944d7c9aa11931" [[package]] name = "predicates-tree" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf" +checksum = "41b740d195ed3166cd147c8047ec98db0e22ec019eb8eeb76d343b795304fb13" dependencies = [ "predicates-core", "termtree", ] +[[package]] +name = "pretty_assertions" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d" +dependencies = [ + "diff", + "yansi", +] + [[package]] name = "primeorder" version = "0.13.6" @@ -6764,18 +7281,18 @@ dependencies = [ "impl-rlp", "impl-serde", "scale-info", - "uint", + "uint 0.9.5", ] [[package]] name = "priority-queue" -version = "2.0.3" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70c501afe3a2e25c9bd219aa56ec1e04cdb3fcdd763055be268778c13fa82c1f" +checksum = "714c75db297bc88a63783ffc6ab9f830698a6705aa0201416931759ef4c8183d" dependencies = [ "autocfg", "equivalent", - "indexmap 2.2.6", + "indexmap 2.6.0", ] [[package]] @@ -6784,17 +7301,17 @@ version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" dependencies = [ - "thiserror", + "thiserror 1.0.69", "toml 0.5.11", ] [[package]] name = "proc-macro-crate" -version = "3.1.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ - "toml_edit 0.21.1", + "toml_edit", ] [[package]] @@ -6821,11 +7338,39 @@ dependencies = [ "version_check", ] +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "proc-macro-hack" +version = "0.5.20+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" + [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" dependencies = [ "unicode-ident", ] @@ -6841,12 +7386,24 @@ dependencies = [ "flate2", "hex", "lazy_static", - "procfs-core", + "procfs-core 0.16.0", "rustix", ] [[package]] -name = "procfs-core" +name = "procfs" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc5b72d8145275d844d4b5f6d4e1eef00c8cd889edb6035c21675d1bb1f45c9f" +dependencies = [ + "bitflags 2.6.0", + "hex", + "procfs-core 0.17.0", + "rustix", +] + +[[package]] +name = "procfs-core" version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d3554923a69f4ce04c4a754260c338f505ce22642d3830e049a399fc2059a29" @@ -6856,6 +7413,16 @@ dependencies = [ "hex", ] +[[package]] +name = "procfs-core" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "239df02d8349b06fc07398a3a1697b06418223b1c7725085e801e7c0fc6a12ec" +dependencies = [ + "bitflags 2.6.0", + "hex", +] + [[package]] name = "prometheus" version = "0.13.4" @@ -6866,9 +7433,9 @@ dependencies = [ "fnv", "lazy_static", "memchr", - "parking_lot 0.12.3", + "parking_lot", "protobuf", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -6885,7 +7452,7 @@ dependencies = [ "rand 0.8.5", "rand_chacha 0.3.1", "rand_xorshift", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", "rusty-fork", "tempfile", "unarray", @@ -6909,7 +7476,7 @@ checksum = "6ff7ff745a347b87471d859a377a9a404361e7efc2a971d73424a6d183c0fc77" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.87", ] [[package]] @@ -6950,55 +7517,61 @@ dependencies = [ [[package]] name = "quinn" -version = "0.11.2" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4ceeeeabace7857413798eb1ffa1e9c905a9946a57d81fb69b4b71c4d8eb3ad" +checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef" dependencies = [ "bytes", "pin-project-lite", "quinn-proto", "quinn-udp", - "rustc-hash 1.1.0", - "rustls 0.23.12", - "thiserror", + "rustc-hash 2.0.0", + "rustls 0.23.16", + "socket2", + "thiserror 2.0.3", "tokio", "tracing", ] [[package]] name = "quinn-proto" -version = "0.11.3" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddf517c03a109db8100448a4be38d498df8a210a99fe0e1b9eaf39e78c640efe" +checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d" dependencies = [ "bytes", + "getrandom 0.2.15", "rand 0.8.5", "ring", - "rustc-hash 1.1.0", - "rustls 0.23.12", + "rustc-hash 2.0.0", + "rustls 0.23.16", + "rustls-pki-types", "slab", - "thiserror", + "thiserror 2.0.3", "tinyvec", "tracing", + "web-time", ] [[package]] name = "quinn-udp" -version = "0.5.4" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bffec3605b73c6f1754535084a85229fa8a30f86014e6c81aeec4abb68b0285" +checksum = "7d5a626c6807713b15cac82a6acaccd6043c9a5408c24baae07611fec3f243da" dependencies = [ + "cfg_aliases", "libc", "once_cell", - "socket2 0.5.7", - "windows-sys 0.52.0", + "socket2", + "tracing", + "windows-sys 0.59.0", ] [[package]] name = "quote" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -7009,16 +7582,6 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" -[[package]] -name = "radix_trie" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" -dependencies = [ - "endian-type", - "nibble_vec", -] - [[package]] name = "rand" version = "0.7.3" @@ -7041,6 +7604,7 @@ dependencies = [ "libc", "rand_chacha 0.3.1", "rand_core 0.6.4", + "serde", ] [[package]] @@ -7111,30 +7675,30 @@ dependencies = [ [[package]] name = "ratatui" -version = "0.27.0" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d16546c5b5962abf8ce6e2881e722b4e0ae3b6f1a08a26ae3573c55853ca68d3" +checksum = "fdef7f9be5c0122f890d58bdf4d964349ba6a6161f705907526d891efabba57d" dependencies = [ "bitflags 2.6.0", "cassowary", "compact_str", "crossterm", + "instability", "itertools 0.13.0", "lru", "paste", - "stability", "strum", "strum_macros 0.26.4", "unicode-segmentation", "unicode-truncate", - "unicode-width", + "unicode-width 0.1.14", ] [[package]] name = "raw-cpuid" -version = "11.1.0" +version = "11.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb9ee317cfe3fbd54b36a511efc1edd42e216903c9cd575e686dd68a2ba90d8d" +checksum = "1ab240315c661615f2ee9f0f2cd32d5a7343a84d5ebcccb99d46e6637565e7b0" dependencies = [ "bitflags 2.6.0", ] @@ -7170,7 +7734,7 @@ dependencies = [ "alloy-json-rpc", "alloy-network", "alloy-node-bindings", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", "alloy-provider", "alloy-pubsub", "alloy-rlp", @@ -7185,9 +7749,9 @@ dependencies = [ "async-trait", "atoi", "beacon-api-client", - "bigdecimal 0.4.5", + "bigdecimal 0.4.6", "built", - "clap 4.5.19", + "clap 4.5.21", "criterion 0.5.1", "crossbeam", "crossbeam-queue", @@ -7203,13 +7767,14 @@ dependencies = [ "eyre", "flate2", "flume", + "foldhash", "futures", "governor", "humantime", - "hyper 1.4.1", + "hyper 1.5.0", "integer-encoding", "itertools 0.11.0", - "jsonrpsee 0.20.3", + "jsonrpsee 0.20.4", "lazy_static", "lru", "lz4_flex", @@ -7218,14 +7783,14 @@ dependencies = [ "mev-share-sse", "mockall", "once_cell", - "parking_lot 0.12.3", + "parking_lot", "primitive-types", "priority-queue", "prometheus", "rand 0.8.5", "rayon", "redis", - "reqwest 0.12.8", + "reqwest 0.12.9", "reth", "reth-basic-payload-builder", "reth-chainspec", @@ -7237,6 +7802,7 @@ dependencies = [ "reth-libmdbx", "reth-node-api", "reth-node-core", + "reth-node-ethereum", "reth-payload-builder", "reth-primitives", "reth-provider", @@ -7256,12 +7822,12 @@ dependencies = [ "ssz_rs_derive 0.9.0 (git+https://github.com/ralexstokes/ssz-rs.git)", "tempfile", "test_utils", - "thiserror", + "thiserror 1.0.69", "time", "tokio", "tokio-stream", "tokio-util", - "toml 0.8.15", + "toml 0.8.19", "tracing", "tracing-subscriber", "tungstenite 0.23.0", @@ -7275,13 +7841,14 @@ dependencies = [ name = "rbuilder-bundle-pool-operations" version = "0.1.0" dependencies = [ + "alloy-primitives 0.8.12", + "alloy-rpc-types-beacon", "derive_more 1.0.0", "eyre", "rbuilder", "reth-db-api", "reth-primitives", "reth-provider", - "reth-rpc-types", "tokio", "tokio-util", "tracing", @@ -7305,58 +7872,40 @@ dependencies = [ "percent-encoding", "ryu", "sha1_smol", - "socket2 0.5.7", + "socket2", "url", ] [[package]] name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "redox_syscall" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "redox_syscall" -version = "0.5.3" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ "bitflags 2.6.0", ] [[package]] name = "redox_users" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom 0.2.15", "libredox", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "regex" -version = "1.10.5" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.7", - "regex-syntax 0.8.4", + "regex-automata 0.4.9", + "regex-syntax 0.8.5", ] [[package]] @@ -7370,13 +7919,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", ] [[package]] @@ -7387,9 +7936,19 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "regress" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "1541daf4e4ed43a0922b7969bdc2170178bcacc5dabf7e39bc508a9fa3953a7a" +dependencies = [ + "hashbrown 0.14.5", + "memchr", +] [[package]] name = "reqwest" @@ -7405,7 +7964,7 @@ dependencies = [ "h2 0.3.26", "http 0.2.12", "http-body 0.4.6", - "hyper 0.14.30", + "hyper 0.14.31", "hyper-tls 0.5.0", "ipnet", "js-sys", @@ -7435,9 +7994,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.8" +version = "0.12.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b" +checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" dependencies = [ "base64 0.22.1", "bytes", @@ -7445,12 +8004,12 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2 0.4.5", + "h2 0.4.6", "http 1.1.0", "http-body 1.0.1", "http-body-util", - "hyper 1.4.1", - "hyper-rustls 0.27.2", + "hyper 1.5.0", + "hyper-rustls 0.27.3", "hyper-tls 0.6.0", "hyper-util", "ipnet", @@ -7462,9 +8021,9 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.12", + "rustls 0.23.16", "rustls-native-certs 0.8.0", - "rustls-pemfile 2.1.2", + "rustls-pemfile 2.2.0", "rustls-pki-types", "serde", "serde_json", @@ -7479,7 +8038,7 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots 0.26.3", + "webpki-roots 0.26.6", "windows-registry", ] @@ -7495,24 +8054,24 @@ dependencies = [ [[package]] name = "reth" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives 0.8.12", "alloy-rlp", + "alloy-rpc-types", "aquamarine", "backon", - "clap 4.5.19", - "discv5", + "clap 4.5.21", "eyre", - "fdlimit", "futures", - "itertools 0.13.0", - "libc", - "metrics-process", "reth-basic-payload-builder", "reth-beacon-consensus", "reth-blockchain-tree", "reth-chainspec", + "reth-cli", "reth-cli-commands", "reth-cli-runner", "reth-cli-util", @@ -7521,10 +8080,10 @@ dependencies = [ "reth-consensus-common", "reth-db", "reth-db-api", - "reth-db-common", "reth-downloaders", "reth-engine-util", "reth-errors", + "reth-ethereum-cli", "reth-ethereum-payload-builder", "reth-evm", "reth-execution-types", @@ -7539,10 +8098,6 @@ dependencies = [ "reth-node-ethereum", "reth-node-events", "reth-node-metrics", - "reth-node-optimism", - "reth-optimism-cli", - "reth-optimism-primitives", - "reth-optimism-rpc", "reth-payload-builder", "reth-payload-primitives", "reth-payload-validator", @@ -7555,32 +8110,28 @@ dependencies = [ "reth-rpc-builder", "reth-rpc-eth-types", "reth-rpc-server-types", - "reth-rpc-types", "reth-rpc-types-compat", "reth-stages", - "reth-stages-api", "reth-static-file", - "reth-static-file-types", "reth-tasks", "reth-tracing", "reth-transaction-pool", "reth-trie", "reth-trie-db", - "serde", "serde_json", "similar-asserts", - "tempfile", - "tikv-jemallocator", "tokio", - "toml 0.8.15", "tracing", ] [[package]] name = "reth-auto-seal-consensus" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ + "alloy-eips", + "alloy-primitives 0.8.12", + "alloy-rpc-types-engine", "futures-util", "reth-beacon-consensus", "reth-chainspec", @@ -7591,14 +8142,15 @@ dependencies = [ "reth-execution-types", "reth-network-p2p", "reth-network-peers", + "reth-optimism-consensus", "reth-primitives", "reth-provider", "reth-revm", - "reth-rpc-types", "reth-stages-api", "reth-tokio-util", "reth-transaction-pool", "reth-trie", + "revm-primitives", "tokio", "tokio-stream", "tracing", @@ -7606,14 +8158,18 @@ dependencies = [ [[package]] name = "reth-basic-payload-builder" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives 0.8.12", "alloy-rlp", "futures-core", "futures-util", "metrics", "reth-chainspec", + "reth-evm", "reth-metrics", "reth-payload-builder", "reth-payload-primitives", @@ -7629,33 +8185,35 @@ dependencies = [ [[package]] name = "reth-beacon-consensus" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ + "alloy-eips", + "alloy-primitives 0.8.12", + "alloy-rpc-types-engine", "futures", "itertools 0.13.0", "metrics", "reth-blockchain-tree-api", "reth-chainspec", - "reth-db-api", "reth-engine-primitives", "reth-errors", "reth-ethereum-consensus", "reth-metrics", "reth-network-p2p", + "reth-node-types", "reth-payload-builder", "reth-payload-primitives", "reth-payload-validator", "reth-primitives", "reth-provider", "reth-prune", - "reth-rpc-types", "reth-stages-api", "reth-static-file", "reth-tasks", "reth-tokio-util", "schnellru", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-stream", "tracing", @@ -7663,13 +8221,15 @@ dependencies = [ [[package]] name = "reth-blockchain-tree" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ + "alloy-eips", + "alloy-primitives 0.8.12", "aquamarine", "linked_hash_set", "metrics", - "parking_lot 0.12.3", + "parking_lot", "reth-blockchain-tree-api", "reth-consensus", "reth-db", @@ -7679,9 +8239,9 @@ dependencies = [ "reth-execution-types", "reth-metrics", "reth-network", + "reth-node-types", "reth-primitives", "reth-provider", - "reth-prune-types", "reth-revm", "reth-stages-api", "reth-storage-errors", @@ -7694,27 +8254,32 @@ dependencies = [ [[package]] name = "reth-blockchain-tree-api" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ + "alloy-eips", + "alloy-primitives 0.8.12", "reth-consensus", "reth-execution-errors", "reth-primitives", "reth-storage-errors", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "reth-chain-state" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives 0.8.12", "alloy-signer", "alloy-signer-local", "auto_impl", "derive_more 1.0.0", "metrics", - "parking_lot 0.12.3", + "parking_lot", "pin-project", "rand 0.8.5", "reth-chainspec", @@ -7732,44 +8297,49 @@ dependencies = [ [[package]] name = "reth-chainspec" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ "alloy-chains", + "alloy-consensus", "alloy-eips", "alloy-genesis", - "alloy-primitives 0.8.0", - "alloy-trie", + "alloy-primitives 0.8.12", "auto_impl", "derive_more 1.0.0", "once_cell", - "op-alloy-rpc-types", "reth-ethereum-forks", "reth-network-peers", "reth-primitives-traits", "reth-trie-common", - "serde", "serde_json", ] [[package]] name = "reth-cli" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ - "clap 4.5.19", + "alloy-genesis", + "clap 4.5.21", "eyre", "reth-cli-runner", + "reth-db", + "serde_json", + "shellexpand", ] [[package]] name = "reth-cli-commands" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ "ahash", + "alloy-eips", + "alloy-primitives 0.8.12", + "alloy-rlp", "backon", - "clap 4.5.19", + "clap 4.5.21", "comfy-table", "crossterm", "eyre", @@ -7780,6 +8350,7 @@ dependencies = [ "ratatui", "reth-beacon-consensus", "reth-chainspec", + "reth-cli", "reth-cli-runner", "reth-cli-util", "reth-config", @@ -7790,6 +8361,7 @@ dependencies = [ "reth-downloaders", "reth-ecies", "reth-eth-wire", + "reth-ethereum-cli", "reth-evm", "reth-exex", "reth-fs-util", @@ -7812,14 +8384,14 @@ dependencies = [ "serde", "serde_json", "tokio", - "toml 0.8.15", + "toml 0.8.19", "tracing", ] [[package]] name = "reth-cli-runner" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ "reth-tasks", "tokio", @@ -7828,50 +8400,56 @@ dependencies = [ [[package]] name = "reth-cli-util" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ "alloy-eips", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", + "cfg-if", "eyre", "libc", "rand 0.8.5", "reth-fs-util", "secp256k1", - "thiserror", + "serde", + "thiserror 1.0.69", + "tikv-jemallocator", ] [[package]] name = "reth-codecs" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ "alloy-consensus", "alloy-eips", "alloy-genesis", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", "alloy-trie", + "arbitrary", "bytes", "modular-bitfield", + "op-alloy-consensus", "reth-codecs-derive", "serde", + "visibility", ] [[package]] name = "reth-codecs-derive" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ "convert_case 0.6.0", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.87", ] [[package]] name = "reth-config" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ "eyre", "humantime-serde", @@ -7879,14 +8457,16 @@ dependencies = [ "reth-prune-types", "reth-stages-types", "serde", - "toml 0.8.15", + "toml 0.8.19", ] [[package]] name = "reth-consensus" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ + "alloy-eips", + "alloy-primitives 0.8.12", "auto_impl", "derive_more 1.0.0", "reth-primitives", @@ -7894,31 +8474,36 @@ dependencies = [ [[package]] name = "reth-consensus-common" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives 0.8.12", "reth-chainspec", "reth-consensus", "reth-primitives", + "revm-primitives", ] [[package]] name = "reth-consensus-debug-client" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ "alloy-consensus", "alloy-eips", + "alloy-primitives 0.8.12", "alloy-provider", + "alloy-rpc-types", + "alloy-rpc-types-engine", "auto_impl", "eyre", "futures", - "reqwest 0.12.8", + "reqwest 0.12.9", "reth-node-api", - "reth-node-core", "reth-rpc-api", "reth-rpc-builder", - "reth-rpc-types", "reth-tracing", "ringbuffer", "serde", @@ -7927,14 +8512,16 @@ dependencies = [ [[package]] name = "reth-db" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ + "alloy-primitives 0.8.12", "bytes", "derive_more 1.0.0", "eyre", "metrics", "page_size", + "parking_lot", "paste", "reth-db-api", "reth-fs-util", @@ -7951,16 +8538,18 @@ dependencies = [ "rustc-hash 2.0.0", "serde", "strum", - "sysinfo 0.30.13", + "sysinfo 0.31.4", "tempfile", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "reth-db-api" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ + "alloy-genesis", + "alloy-primitives 0.8.12", "arbitrary", "bytes", "derive_more 1.0.0", @@ -7981,10 +8570,11 @@ dependencies = [ [[package]] name = "reth-db-common" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ "alloy-genesis", + "alloy-primitives 0.8.12", "boyer-moore-magiclen", "eyre", "reth-chainspec", @@ -7994,6 +8584,7 @@ dependencies = [ "reth-db-api", "reth-etl", "reth-fs-util", + "reth-node-types", "reth-primitives", "reth-provider", "reth-stages-types", @@ -8001,35 +8592,38 @@ dependencies = [ "reth-trie-db", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "tracing", ] [[package]] name = "reth-db-models" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ + "alloy-primitives 0.8.12", "arbitrary", "bytes", "modular-bitfield", "proptest", "reth-codecs", - "reth-primitives", + "reth-primitives-traits", "serde", ] [[package]] name = "reth-discv4" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", "alloy-rlp", "discv5", "enr 0.12.1", "generic-array", - "parking_lot 0.12.3", + "itertools 0.13.0", + "parking_lot", + "rand 0.8.5", "reth-ethereum-forks", "reth-net-banlist", "reth-net-nat", @@ -8037,7 +8631,7 @@ dependencies = [ "schnellru", "secp256k1", "serde", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-stream", "tracing", @@ -8045,10 +8639,10 @@ dependencies = [ [[package]] name = "reth-discv5" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", "alloy-rlp", "derive_more 1.0.0", "discv5", @@ -8062,27 +8656,29 @@ dependencies = [ "reth-metrics", "reth-network-peers", "secp256k1", - "thiserror", + "thiserror 1.0.69", "tokio", "tracing", ] [[package]] name = "reth-dns-discovery" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", "data-encoding", "enr 0.12.1", "linked_hash_set", - "parking_lot 0.12.3", + "parking_lot", "reth-ethereum-forks", "reth-network-peers", "reth-tokio-util", "schnellru", "secp256k1", - "thiserror", + "serde", + "serde_with", + "thiserror 1.0.69", "tokio", "tokio-stream", "tracing", @@ -8091,9 +8687,11 @@ dependencies = [ [[package]] name = "reth-downloaders" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ + "alloy-eips", + "alloy-primitives 0.8.12", "alloy-rlp", "futures", "futures-util", @@ -8109,7 +8707,7 @@ dependencies = [ "reth-primitives", "reth-storage-api", "reth-tasks", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-stream", "tokio-util", @@ -8118,11 +8716,11 @@ dependencies = [ [[package]] name = "reth-ecies" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ "aes", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", "alloy-rlp", "block-padding", "byteorder", @@ -8139,7 +8737,7 @@ dependencies = [ "secp256k1", "sha2 0.10.8", "sha3", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-stream", "tokio-util", @@ -8148,53 +8746,88 @@ dependencies = [ ] [[package]] -name = "reth-engine-primitives" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +name = "reth-engine-local" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ + "alloy-primitives 0.8.12", + "alloy-rpc-types-engine", + "eyre", + "futures-util", + "op-alloy-rpc-types-engine", + "reth-beacon-consensus", "reth-chainspec", + "reth-consensus", + "reth-engine-primitives", + "reth-engine-service", + "reth-engine-tree", + "reth-ethereum-engine-primitives", + "reth-evm", + "reth-payload-builder", + "reth-payload-primitives", + "reth-payload-validator", + "reth-provider", + "reth-prune", + "reth-rpc-types-compat", + "reth-stages-api", + "reth-transaction-pool", + "tokio", + "tokio-stream", + "tracing", +] + +[[package]] +name = "reth-engine-primitives" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" +dependencies = [ + "alloy-primitives 0.8.12", + "reth-execution-types", "reth-payload-primitives", + "reth-primitives", + "reth-trie", "serde", ] [[package]] name = "reth-engine-service" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ "futures", "pin-project", "reth-beacon-consensus", "reth-chainspec", "reth-consensus", - "reth-db-api", - "reth-engine-primitives", "reth-engine-tree", "reth-evm", "reth-network-p2p", + "reth-node-types", "reth-payload-builder", "reth-payload-validator", "reth-provider", "reth-prune", "reth-stages-api", "reth-tasks", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "reth-engine-tree" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ + "alloy-eips", + "alloy-primitives 0.8.12", + "alloy-rpc-types-engine", "futures", "metrics", "reth-beacon-consensus", "reth-blockchain-tree", "reth-blockchain-tree-api", "reth-chain-state", + "reth-chainspec", "reth-consensus", - "reth-db", - "reth-db-api", "reth-engine-primitives", "reth-errors", "reth-evm", @@ -8207,20 +8840,26 @@ dependencies = [ "reth-provider", "reth-prune", "reth-revm", - "reth-rpc-types", "reth-stages-api", "reth-tasks", "reth-trie", - "thiserror", + "reth-trie-parallel", + "revm-primitives", + "thiserror 1.0.69", "tokio", + "tokio-stream", "tracing", ] [[package]] name = "reth-engine-util" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives 0.8.12", + "alloy-rpc-types-engine", "eyre", "futures", "itertools 0.13.0", @@ -8235,7 +8874,6 @@ dependencies = [ "reth-primitives", "reth-provider", "reth-revm", - "reth-rpc-types", "reth-rpc-types-compat", "reth-trie", "revm-primitives", @@ -8248,22 +8886,23 @@ dependencies = [ [[package]] name = "reth-errors" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ "reth-blockchain-tree-api", "reth-consensus", "reth-execution-errors", "reth-fs-util", "reth-storage-errors", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "reth-eth-wire" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ + "alloy-primitives 0.8.12", "alloy-rlp", "bytes", "derive_more 1.0.0", @@ -8276,8 +8915,9 @@ dependencies = [ "reth-metrics", "reth-network-peers", "reth-primitives", + "serde", "snap", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-stream", "tokio-util", @@ -8286,25 +8926,40 @@ dependencies = [ [[package]] name = "reth-eth-wire-types" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ "alloy-chains", - "alloy-genesis", + "alloy-eips", + "alloy-primitives 0.8.12", "alloy-rlp", "bytes", "derive_more 1.0.0", "reth-chainspec", "reth-codecs-derive", "reth-primitives", - "thiserror", + "serde", + "thiserror 1.0.69", ] [[package]] -name = "reth-ethereum-consensus" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +name = "reth-ethereum-cli" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" +dependencies = [ + "eyre", + "reth-chainspec", + "reth-cli", +] + +[[package]] +name = "reth-ethereum-consensus" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives 0.8.12", "reth-chainspec", "reth-consensus", "reth-consensus-common", @@ -8314,29 +8969,30 @@ dependencies = [ [[package]] name = "reth-ethereum-engine-primitives" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ + "alloy-eips", + "alloy-primitives 0.8.12", "alloy-rlp", + "alloy-rpc-types-engine", + "reth-chain-state", "reth-chainspec", "reth-engine-primitives", - "reth-evm-ethereum", "reth-payload-primitives", "reth-primitives", - "reth-rpc-types", "reth-rpc-types-compat", - "revm-primitives", "serde", "sha2 0.10.8", ] [[package]] name = "reth-ethereum-forks" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ "alloy-chains", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", "alloy-rlp", "arbitrary", "auto_impl", @@ -8352,28 +9008,35 @@ dependencies = [ [[package]] name = "reth-ethereum-payload-builder" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives 0.8.12", "reth-basic-payload-builder", + "reth-chain-state", + "reth-chainspec", "reth-errors", "reth-evm", "reth-evm-ethereum", "reth-execution-types", "reth-payload-builder", + "reth-payload-primitives", "reth-primitives", "reth-provider", "reth-revm", "reth-transaction-pool", "reth-trie", "revm", + "revm-primitives", "tracing", ] [[package]] name = "reth-etl" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ "rayon", "reth-db-api", @@ -8382,17 +9045,25 @@ dependencies = [ [[package]] name = "reth-evm" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ "alloy-eips", + "alloy-primitives 0.8.12", "auto_impl", "futures-util", + "metrics", + "parking_lot", "reth-chainspec", + "reth-consensus", + "reth-consensus-common", "reth-execution-errors", "reth-execution-types", + "reth-metrics", "reth-primitives", + "reth-primitives-traits", "reth-prune-types", + "reth-revm", "reth-storage-errors", "revm", "revm-primitives", @@ -8400,49 +9071,30 @@ dependencies = [ [[package]] name = "reth-evm-ethereum" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ + "alloy-consensus", "alloy-eips", + "alloy-primitives 0.8.12", "alloy-sol-types", "reth-chainspec", + "reth-consensus", "reth-ethereum-consensus", "reth-ethereum-forks", "reth-evm", - "reth-execution-types", "reth-primitives", - "reth-prune-types", "reth-revm", "revm-primitives", ] -[[package]] -name = "reth-evm-optimism" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" -dependencies = [ - "reth-chainspec", - "reth-ethereum-forks", - "reth-evm", - "reth-execution-errors", - "reth-execution-types", - "reth-optimism-consensus", - "reth-primitives", - "reth-prune-types", - "reth-revm", - "revm", - "revm-primitives", - "thiserror", - "tracing", -] - [[package]] name = "reth-execution-errors" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ "alloy-eips", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", "alloy-rlp", "derive_more 1.0.0", "nybbles", @@ -8454,27 +9106,37 @@ dependencies = [ [[package]] name = "reth-execution-types" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ - "reth-chainspec", + "alloy-eips", + "alloy-primitives 0.8.12", "reth-execution-errors", "reth-primitives", "reth-trie", "revm", + "serde", + "serde_with", ] [[package]] name = "reth-exex" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ + "alloy-eips", + "alloy-primitives 0.8.12", "eyre", "futures", + "itertools 0.13.0", "metrics", + "parking_lot", + "reth-chain-state", + "reth-chainspec", "reth-config", "reth-evm", "reth-exex-types", + "reth-fs-util", "reth-metrics", "reth-node-api", "reth-node-core", @@ -8487,70 +9149,102 @@ dependencies = [ "reth-stages-api", "reth-tasks", "reth-tracing", + "rmp-serde", "tokio", "tokio-util", + "tracing", ] [[package]] name = "reth-exex-types" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ - "alloy-primitives 0.8.0", - "reth-provider", + "alloy-eips", + "alloy-primitives 0.8.12", + "reth-chain-state", + "reth-execution-types", + "serde", + "serde_with", ] [[package]] name = "reth-fs-util" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", +] + +[[package]] +name = "reth-invalid-block-hooks" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" +dependencies = [ + "alloy-primitives 0.8.12", + "alloy-rlp", + "alloy-rpc-types-debug", + "eyre", + "futures", + "jsonrpsee 0.24.7", + "pretty_assertions", + "reth-chainspec", + "reth-engine-primitives", + "reth-evm", + "reth-primitives", + "reth-provider", + "reth-revm", + "reth-rpc-api", + "reth-tracing", + "reth-trie", + "serde", + "serde_json", ] [[package]] name = "reth-ipc" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ "async-trait", "bytes", "futures", "futures-util", "interprocess", - "jsonrpsee 0.24.4", + "jsonrpsee 0.24.7", "pin-project", "serde_json", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-stream", "tokio-util", - "tower", + "tower 0.4.13", "tracing", ] [[package]] name = "reth-libmdbx" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ "bitflags 2.6.0", "byteorder", "dashmap 6.1.0", "derive_more 1.0.0", - "indexmap 2.2.6", - "parking_lot 0.12.3", + "indexmap 2.6.0", + "parking_lot", "reth-mdbx-sys", - "thiserror", + "smallvec", + "thiserror 1.0.69", "tracing", ] [[package]] name = "reth-mdbx-sys" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ "bindgen", "cc", @@ -8558,52 +9252,45 @@ dependencies = [ [[package]] name = "reth-metrics" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ "futures", "metrics", - "reth-metrics-derive", + "metrics-derive", "tokio", "tokio-util", ] -[[package]] -name = "reth-metrics-derive" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" -dependencies = [ - "proc-macro2", - "quote", - "regex", - "syn 2.0.72", -] - [[package]] name = "reth-net-banlist" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", ] [[package]] name = "reth-net-nat" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ "futures-util", - "reqwest 0.12.8", + "if-addrs", + "reqwest 0.12.9", "serde_with", - "thiserror", + "thiserror 1.0.69", "tokio", + "tracing", ] [[package]] name = "reth-network" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ + "alloy-eips", + "alloy-primitives 0.8.12", "alloy-rlp", "aquamarine", "auto_impl", @@ -8613,7 +9300,7 @@ dependencies = [ "futures", "itertools 0.13.0", "metrics", - "parking_lot 0.12.3", + "parking_lot", "pin-project", "rand 0.8.5", "reth-chainspec", @@ -8631,6 +9318,7 @@ dependencies = [ "reth-network-peers", "reth-network-types", "reth-primitives", + "reth-provider", "reth-storage-api", "reth-tasks", "reth-tokio-util", @@ -8640,7 +9328,7 @@ dependencies = [ "secp256k1", "serde", "smallvec", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-stream", "tokio-util", @@ -8649,10 +9337,10 @@ dependencies = [ [[package]] name = "reth-network-api" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", "alloy-rpc-types-admin", "auto_impl", "derive_more 1.0.0", @@ -8665,19 +9353,22 @@ dependencies = [ "reth-network-types", "reth-tokio-util", "serde", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-stream", ] [[package]] name = "reth-network-p2p" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ + "alloy-eips", + "alloy-primitives 0.8.12", "auto_impl", "derive_more 1.0.0", "futures", + "parking_lot", "reth-consensus", "reth-eth-wire-types", "reth-network-peers", @@ -8690,23 +9381,23 @@ dependencies = [ [[package]] name = "reth-network-peers" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", "alloy-rlp", "enr 0.12.1", "secp256k1", "serde_with", - "thiserror", + "thiserror 1.0.69", "tokio", "url", ] [[package]] name = "reth-network-types" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ "humantime-serde", "reth-ethereum-forks", @@ -8719,56 +9410,60 @@ dependencies = [ [[package]] name = "reth-nippy-jar" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ "anyhow", "bincode", - "cuckoofilter", "derive_more 1.0.0", "lz4_flex", - "memmap2 0.9.4", - "ph", + "memmap2 0.9.5", "reth-fs-util", "serde", - "sucds", - "thiserror", + "thiserror 1.0.69", "tracing", "zstd 0.13.2", ] [[package]] name = "reth-node-api" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ - "reth-chainspec", - "reth-db-api", + "alloy-rpc-types-engine", + "eyre", + "reth-beacon-consensus", + "reth-consensus", "reth-engine-primitives", "reth-evm", "reth-network-api", + "reth-node-core", + "reth-node-types", "reth-payload-builder", "reth-payload-primitives", + "reth-primitives", "reth-provider", - "reth-rpc-eth-api", "reth-tasks", "reth-transaction-pool", ] [[package]] name = "reth-node-builder" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ - "alloy-network", + "alloy-primitives 0.8.12", + "alloy-rpc-types", "aquamarine", "eyre", "fdlimit", "futures", + "jsonrpsee 0.24.7", "rayon", "reth-auto-seal-consensus", "reth-beacon-consensus", "reth-blockchain-tree", + "reth-chain-state", "reth-chainspec", "reth-cli-util", "reth-config", @@ -8777,11 +9472,14 @@ dependencies = [ "reth-db-api", "reth-db-common", "reth-downloaders", + "reth-engine-local", "reth-engine-service", "reth-engine-tree", "reth-engine-util", "reth-evm", "reth-exex", + "reth-fs-util", + "reth-invalid-block-hooks", "reth-network", "reth-network-api", "reth-network-p2p", @@ -8790,16 +9488,17 @@ dependencies = [ "reth-node-events", "reth-node-metrics", "reth-payload-builder", + "reth-payload-primitives", "reth-payload-validator", "reth-primitives", "reth-provider", "reth-prune", "reth-rpc", + "reth-rpc-api", "reth-rpc-builder", "reth-rpc-engine-api", "reth-rpc-eth-types", "reth-rpc-layer", - "reth-rpc-types", "reth-stages", "reth-static-file", "reth-tasks", @@ -8814,12 +9513,14 @@ dependencies = [ [[package]] name = "reth-node-core" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ - "alloy-genesis", + "alloy-consensus", + "alloy-eips", + "alloy-primitives 0.8.12", "alloy-rpc-types-engine", - "clap 4.5.19", + "clap 4.5.21", "const_format", "derive_more 1.0.0", "dirs-next", @@ -8832,41 +9533,36 @@ dependencies = [ "reth-config", "reth-consensus-common", "reth-db", - "reth-db-api", "reth-discv4", "reth-discv5", - "reth-fs-util", "reth-net-nat", "reth-network", "reth-network-p2p", "reth-network-peers", - "reth-optimism-chainspec", "reth-primitives", - "reth-provider", "reth-prune-types", - "reth-rpc-api", - "reth-rpc-eth-api", "reth-rpc-eth-types", "reth-rpc-server-types", - "reth-rpc-types", "reth-rpc-types-compat", "reth-stages-types", + "reth-storage-api", "reth-storage-errors", "reth-tracing", "reth-transaction-pool", "secp256k1", "serde", - "serde_json", "shellexpand", - "toml 0.8.15", + "strum", + "thiserror 1.0.69", + "toml 0.8.19", "tracing", "vergen", ] [[package]] name = "reth-node-ethereum" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ "eyre", "reth-auto-seal-consensus", @@ -8876,22 +9572,30 @@ dependencies = [ "reth-consensus", "reth-ethereum-engine-primitives", "reth-ethereum-payload-builder", + "reth-evm", "reth-evm-ethereum", "reth-network", "reth-node-api", "reth-node-builder", "reth-payload-builder", + "reth-primitives", "reth-provider", + "reth-revm", "reth-rpc", "reth-tracing", "reth-transaction-pool", + "reth-trie-db", + "revm", ] [[package]] name = "reth-node-events" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives 0.8.12", "alloy-rpc-types-engine", "futures", "humantime", @@ -8899,7 +9603,6 @@ dependencies = [ "reth-beacon-consensus", "reth-network", "reth-network-api", - "reth-primitives", "reth-primitives-traits", "reth-provider", "reth-prune", @@ -8911,112 +9614,92 @@ dependencies = [ [[package]] name = "reth-node-metrics" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ "eyre", "http 1.1.0", - "jsonrpsee 0.24.4", + "jsonrpsee 0.24.7", "metrics", "metrics-exporter-prometheus", "metrics-process", "metrics-util", - "procfs", + "procfs 0.16.0", "reth-db-api", "reth-metrics", "reth-provider", "reth-tasks", "tikv-jemalloc-ctl", "tokio", - "tower", + "tower 0.4.13", "tracing", "vergen", ] [[package]] -name = "reth-node-optimism" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +name = "reth-node-types" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ - "async-trait", - "clap 4.5.19", - "eyre", - "jsonrpsee 0.24.4", - "jsonrpsee-types 0.24.4", - "parking_lot 0.12.3", - "reqwest 0.12.8", - "reth-auto-seal-consensus", - "reth-basic-payload-builder", - "reth-beacon-consensus", "reth-chainspec", - "reth-consensus", - "reth-discv5", - "reth-evm", - "reth-evm-optimism", - "reth-network", - "reth-node-api", - "reth-node-builder", - "reth-optimism-chainspec", - "reth-optimism-consensus", - "reth-optimism-payload-builder", - "reth-optimism-rpc", - "reth-payload-builder", + "reth-db-api", + "reth-engine-primitives", "reth-primitives", - "reth-provider", - "reth-revm", - "reth-rpc", - "reth-rpc-eth-api", - "reth-rpc-eth-types", - "reth-rpc-types", - "reth-rpc-types-compat", - "reth-tracing", - "reth-transaction-pool", - "serde", - "serde_json", - "thiserror", - "tracing", + "reth-primitives-traits", + "reth-trie-db", ] [[package]] name = "reth-optimism-chainspec" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ "alloy-chains", - "alloy-primitives 0.8.0", + "alloy-consensus", + "alloy-eips", + "alloy-genesis", + "alloy-primitives 0.8.12", "derive_more 1.0.0", "once_cell", + "op-alloy-rpc-types", "reth-chainspec", "reth-ethereum-forks", + "reth-network-peers", + "reth-optimism-forks", "reth-primitives-traits", "serde_json", ] [[package]] name = "reth-optimism-cli" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", "alloy-rlp", - "clap 4.5.19", + "clap 4.5.21", "eyre", "futures-util", "reth-chainspec", "reth-cli", "reth-cli-commands", + "reth-cli-runner", "reth-config", "reth-consensus", "reth-db", "reth-db-api", + "reth-db-common", "reth-downloaders", "reth-errors", - "reth-evm-optimism", "reth-execution-types", "reth-network-p2p", + "reth-node-builder", "reth-node-core", "reth-node-events", + "reth-node-metrics", "reth-optimism-chainspec", + "reth-optimism-evm", + "reth-optimism-node", "reth-optimism-primitives", "reth-primitives", "reth-provider", @@ -9025,6 +9708,7 @@ dependencies = [ "reth-stages-types", "reth-static-file", "reth-static-file-types", + "reth-tracing", "tokio", "tokio-util", "tracing", @@ -9032,97 +9716,199 @@ dependencies = [ [[package]] name = "reth-optimism-consensus" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ + "alloy-consensus", + "alloy-primitives 0.8.12", "reth-chainspec", "reth-consensus", "reth-consensus-common", + "reth-optimism-chainspec", + "reth-optimism-forks", "reth-primitives", + "reth-trie-common", "tracing", ] +[[package]] +name = "reth-optimism-evm" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives 0.8.12", + "derive_more 1.0.0", + "op-alloy-consensus", + "reth-chainspec", + "reth-consensus", + "reth-ethereum-forks", + "reth-evm", + "reth-execution-errors", + "reth-execution-types", + "reth-optimism-chainspec", + "reth-optimism-consensus", + "reth-optimism-forks", + "reth-primitives", + "reth-prune-types", + "reth-revm", + "revm", + "revm-primitives", + "tracing", +] + +[[package]] +name = "reth-optimism-forks" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" +dependencies = [ + "alloy-chains", + "alloy-primitives 0.8.12", + "once_cell", + "reth-ethereum-forks", + "serde", +] + +[[package]] +name = "reth-optimism-node" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" +dependencies = [ + "alloy-eips", + "alloy-primitives 0.8.12", + "alloy-rpc-types-engine", + "clap 4.5.21", + "eyre", + "op-alloy-rpc-types-engine", + "parking_lot", + "reth-auto-seal-consensus", + "reth-basic-payload-builder", + "reth-beacon-consensus", + "reth-chainspec", + "reth-consensus", + "reth-engine-local", + "reth-evm", + "reth-network", + "reth-node-api", + "reth-node-builder", + "reth-optimism-chainspec", + "reth-optimism-consensus", + "reth-optimism-evm", + "reth-optimism-forks", + "reth-optimism-payload-builder", + "reth-optimism-rpc", + "reth-payload-builder", + "reth-primitives", + "reth-provider", + "reth-revm", + "reth-tracing", + "reth-transaction-pool", + "reth-trie-db", + "revm", + "serde", + "serde_json", +] + [[package]] name = "reth-optimism-payload-builder" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives 0.8.12", "alloy-rlp", + "alloy-rpc-types-engine", + "op-alloy-consensus", + "op-alloy-rpc-types-engine", "reth-basic-payload-builder", "reth-chain-state", "reth-chainspec", "reth-evm", - "reth-evm-optimism", "reth-execution-types", + "reth-optimism-chainspec", + "reth-optimism-consensus", + "reth-optimism-evm", + "reth-optimism-forks", "reth-payload-builder", "reth-payload-primitives", "reth-primitives", "reth-provider", "reth-revm", - "reth-rpc-types", "reth-rpc-types-compat", "reth-transaction-pool", "reth-trie", "revm", "sha2 0.10.8", - "thiserror", + "thiserror 1.0.69", "tracing", ] [[package]] name = "reth-optimism-primitives" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" +dependencies = [ + "alloy-consensus", + "alloy-primitives 0.8.12", + "reth-primitives", +] [[package]] name = "reth-optimism-rpc" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ - "alloy-primitives 0.8.0", - "jsonrpsee-types 0.24.4", + "alloy-consensus", + "alloy-eips", + "alloy-primitives 0.8.12", + "alloy-rpc-types", + "alloy-rpc-types-eth", + "derive_more 1.0.0", + "jsonrpsee-types 0.24.7", + "op-alloy-consensus", "op-alloy-network", - "parking_lot 0.12.3", - "reqwest 0.12.8", + "op-alloy-rpc-types", + "parking_lot", + "reqwest 0.12.9", "reth-chainspec", "reth-evm", - "reth-evm-optimism", "reth-network-api", "reth-node-api", "reth-node-builder", + "reth-optimism-chainspec", + "reth-optimism-consensus", + "reth-optimism-evm", + "reth-optimism-forks", "reth-primitives", "reth-provider", "reth-rpc", "reth-rpc-eth-api", "reth-rpc-eth-types", "reth-rpc-server-types", - "reth-rpc-types", "reth-tasks", "reth-transaction-pool", "revm", "serde_json", - "thiserror", + "thiserror 1.0.69", "tokio", "tracing", ] [[package]] name = "reth-payload-builder" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ + "alloy-rpc-types", + "async-trait", "futures-util", "metrics", - "pin-project", - "reth-errors", "reth-ethereum-engine-primitives", "reth-metrics", "reth-payload-primitives", - "reth-primitives", "reth-provider", - "reth-rpc-types", - "reth-transaction-pool", - "thiserror", "tokio", "tokio-stream", "tracing", @@ -9130,40 +9916,46 @@ dependencies = [ [[package]] name = "reth-payload-primitives" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ + "alloy-eips", + "alloy-primitives 0.8.12", + "alloy-rpc-types", + "async-trait", + "op-alloy-rpc-types-engine", + "pin-project", "reth-chain-state", "reth-chainspec", "reth-errors", "reth-primitives", - "reth-rpc-types", "reth-transaction-pool", "serde", - "thiserror", + "thiserror 1.0.69", "tokio", + "tokio-stream", + "tracing", ] [[package]] name = "reth-payload-validator" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ + "alloy-rpc-types", "reth-chainspec", "reth-primitives", - "reth-rpc-types", "reth-rpc-types-compat", ] [[package]] name = "reth-primitives" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ "alloy-consensus", "alloy-eips", - "alloy-genesis", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", "alloy-rlp", "alloy-rpc-types", "alloy-serde", @@ -9171,38 +9963,35 @@ dependencies = [ "bytes", "c-kzg", "derive_more 1.0.0", - "k256 0.13.3", + "k256 0.13.4", "modular-bitfield", "once_cell", + "op-alloy-consensus", "op-alloy-rpc-types", - "proptest", + "rand 0.8.5", "rayon", - "reth-chainspec", "reth-codecs", "reth-ethereum-forks", - "reth-optimism-chainspec", "reth-primitives-traits", "reth-static-file-types", "reth-trie-common", "revm-primitives", "secp256k1", "serde", - "tempfile", - "thiserror", + "serde_with", "zstd 0.13.2", ] [[package]] name = "reth-primitives-traits" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ "alloy-consensus", "alloy-eips", "alloy-genesis", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", "alloy-rlp", - "alloy-rpc-types-eth", "arbitrary", "byteorder", "bytes", @@ -9214,20 +10003,24 @@ dependencies = [ "revm-primitives", "roaring", "serde", + "serde_with", ] [[package]] name = "reth-provider" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives 0.8.12", "alloy-rpc-types-engine", "auto_impl", "dashmap 6.1.0", "itertools 0.13.0", "metrics", - "once_cell", - "parking_lot 0.12.3", + "notify", + "parking_lot", "rayon", "reth-blockchain-tree-api", "reth-chain-state", @@ -9236,12 +10029,15 @@ dependencies = [ "reth-db", "reth-db-api", "reth-errors", + "reth-ethereum-engine-primitives", "reth-evm", "reth-execution-types", "reth-fs-util", "reth-metrics", "reth-network-p2p", "reth-nippy-jar", + "reth-node-types", + "reth-optimism-primitives", "reth-primitives", "reth-prune-types", "reth-stages-types", @@ -9257,10 +10053,10 @@ dependencies = [ [[package]] name = "reth-prune" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", "itertools 0.13.0", "metrics", "rayon", @@ -9276,30 +10072,31 @@ dependencies = [ "reth-static-file-types", "reth-tokio-util", "rustc-hash 2.0.0", - "thiserror", + "thiserror 1.0.69", "tokio", "tracing", ] [[package]] name = "reth-prune-types" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", + "arbitrary", "bytes", "derive_more 1.0.0", "modular-bitfield", "reth-codecs", "serde", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "reth-rbuilder" version = "0.1.0" dependencies = [ - "clap 4.5.19", + "clap 4.5.21", "eyre", "libc", "rbuilder", @@ -9316,48 +10113,64 @@ dependencies = [ [[package]] name = "reth-revm" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ - "reth-chainspec", - "reth-consensus-common", + "alloy-eips", + "alloy-primitives 0.8.12", "reth-execution-errors", "reth-primitives", "reth-prune-types", "reth-storage-api", "reth-storage-errors", + "reth-trie", "revm", ] [[package]] name = "reth-rpc" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ + "alloy-consensus", "alloy-dyn-abi", + "alloy-eips", "alloy-genesis", "alloy-network", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", "alloy-rlp", + "alloy-rpc-types", + "alloy-rpc-types-admin", + "alloy-rpc-types-beacon", + "alloy-rpc-types-debug", + "alloy-rpc-types-eth", + "alloy-rpc-types-mev", + "alloy-rpc-types-trace", + "alloy-rpc-types-txpool", + "alloy-serde", + "alloy-signer", + "alloy-signer-local", "async-trait", "derive_more 1.0.0", "futures", "http 1.1.0", "http-body 1.0.1", - "hyper 1.4.1", - "jsonrpsee 0.24.4", + "hyper 1.5.0", + "jsonrpsee 0.24.7", "jsonwebtoken", - "parking_lot 0.12.3", + "parking_lot", "pin-project", "rand 0.8.5", "reth-chainspec", + "reth-consensus", "reth-consensus-common", "reth-errors", + "reth-ethereum-consensus", "reth-evm", "reth-network-api", "reth-network-peers", "reth-network-types", - "reth-node-api", + "reth-payload-validator", "reth-primitives", "reth-provider", "reth-revm", @@ -9366,7 +10179,6 @@ dependencies = [ "reth-rpc-eth-api", "reth-rpc-eth-types", "reth-rpc-server-types", - "reth-rpc-types", "reth-rpc-types-compat", "reth-tasks", "reth-transaction-pool", @@ -9374,47 +10186,61 @@ dependencies = [ "revm", "revm-inspectors", "revm-primitives", - "secp256k1", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-stream", - "tower", + "tower 0.4.13", "tracing", "tracing-futures", ] [[package]] name = "reth-rpc-api" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ + "alloy-eips", "alloy-json-rpc", - "jsonrpsee 0.24.4", + "alloy-primitives 0.8.12", + "alloy-rpc-types", + "alloy-rpc-types-admin", + "alloy-rpc-types-anvil", + "alloy-rpc-types-beacon", + "alloy-rpc-types-debug", + "alloy-rpc-types-engine", + "alloy-rpc-types-eth", + "alloy-rpc-types-mev", + "alloy-rpc-types-trace", + "alloy-rpc-types-txpool", + "alloy-serde", + "jsonrpsee 0.24.7", "reth-engine-primitives", "reth-network-peers", - "reth-primitives", "reth-rpc-eth-api", - "reth-rpc-types", + "serde", + "serde_with", ] [[package]] name = "reth-rpc-builder" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ "http 1.1.0", - "jsonrpsee 0.24.4", + "jsonrpsee 0.24.7", "metrics", "pin-project", "reth-chainspec", + "reth-consensus", "reth-engine-primitives", "reth-evm", "reth-ipc", "reth-metrics", "reth-network-api", "reth-node-core", + "reth-primitives", "reth-provider", "reth-rpc", "reth-rpc-api", @@ -9422,24 +10248,28 @@ dependencies = [ "reth-rpc-eth-types", "reth-rpc-layer", "reth-rpc-server-types", - "reth-rpc-types", "reth-tasks", "reth-transaction-pool", "serde", - "thiserror", - "tower", + "thiserror 1.0.69", + "tokio", + "tokio-util", + "tower 0.4.13", "tower-http", "tracing", ] [[package]] name = "reth-rpc-engine-api" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ + "alloy-eips", + "alloy-primitives 0.8.12", + "alloy-rpc-types-engine", "async-trait", - "jsonrpsee-core 0.24.4", - "jsonrpsee-types 0.24.4", + "jsonrpsee-core 0.24.7", + "jsonrpsee-types 0.24.7", "metrics", "reth-beacon-consensus", "reth-chainspec", @@ -9450,42 +10280,48 @@ dependencies = [ "reth-payload-primitives", "reth-primitives", "reth-rpc-api", - "reth-rpc-types", "reth-rpc-types-compat", "reth-storage-api", "reth-tasks", + "reth-transaction-pool", "serde", - "thiserror", + "thiserror 1.0.69", "tokio", "tracing", ] [[package]] name = "reth-rpc-eth-api" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ + "alloy-consensus", "alloy-dyn-abi", + "alloy-eips", "alloy-json-rpc", "alloy-network", + "alloy-primitives 0.8.12", + "alloy-rpc-types", + "alloy-rpc-types-eth", + "alloy-rpc-types-mev", "async-trait", "auto_impl", "dyn-clone", "futures", - "jsonrpsee 0.24.4", - "jsonrpsee-types 0.24.4", - "parking_lot 0.12.3", + "jsonrpsee 0.24.7", + "jsonrpsee-types 0.24.7", + "parking_lot", "reth-chainspec", "reth-errors", "reth-evm", "reth-execution-types", "reth-network-api", + "reth-node-api", "reth-primitives", "reth-provider", "reth-revm", "reth-rpc-eth-types", "reth-rpc-server-types", - "reth-rpc-types", "reth-rpc-types-compat", "reth-tasks", "reth-transaction-pool", @@ -9499,14 +10335,20 @@ dependencies = [ [[package]] name = "reth-rpc-eth-types" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives 0.8.12", + "alloy-rpc-types", + "alloy-rpc-types-eth", "alloy-sol-types", "derive_more 1.0.0", "futures", - "jsonrpsee-core 0.24.4", - "jsonrpsee-types 0.24.4", + "itertools 0.13.0", + "jsonrpsee-core 0.24.7", + "jsonrpsee-types 0.24.7", "metrics", "rand 0.8.5", "reth-chain-state", @@ -9518,7 +10360,6 @@ dependencies = [ "reth-primitives", "reth-revm", "reth-rpc-server-types", - "reth-rpc-types", "reth-rpc-types-compat", "reth-storage-api", "reth-tasks", @@ -9529,7 +10370,7 @@ dependencies = [ "revm-primitives", "schnellru", "serde", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-stream", "tracing", @@ -9537,70 +10378,57 @@ dependencies = [ [[package]] name = "reth-rpc-layer" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ "alloy-rpc-types-engine", "http 1.1.0", - "jsonrpsee-http-client 0.24.4", + "jsonrpsee-http-client 0.24.7", "pin-project", - "tower", + "tower 0.4.13", "tracing", ] [[package]] name = "reth-rpc-server-types" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ - "alloy-primitives 0.8.0", - "jsonrpsee-core 0.24.4", - "jsonrpsee-types 0.24.4", + "alloy-eips", + "alloy-primitives 0.8.12", + "alloy-rpc-types-engine", + "jsonrpsee-core 0.24.7", + "jsonrpsee-types 0.24.7", "reth-errors", "reth-network-api", - "reth-primitives", - "reth-rpc-types", "serde", "strum", ] -[[package]] -name = "reth-rpc-types" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" -dependencies = [ - "alloy-primitives 0.8.0", - "alloy-rpc-types", - "alloy-rpc-types-admin", - "alloy-rpc-types-anvil", - "alloy-rpc-types-beacon", - "alloy-rpc-types-engine", - "alloy-rpc-types-mev", - "alloy-rpc-types-trace", - "alloy-rpc-types-txpool", - "alloy-serde", - "jsonrpsee-types 0.24.4", - "op-alloy-rpc-types", - "op-alloy-rpc-types-engine", -] - [[package]] name = "reth-rpc-types-compat" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives 0.8.12", "alloy-rlp", "alloy-rpc-types", + "alloy-rpc-types-engine", + "alloy-rpc-types-eth", "reth-primitives", - "reth-rpc-types", "reth-trie-common", + "serde", ] [[package]] name = "reth-stages" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ + "alloy-primitives 0.8.12", + "bincode", "futures-util", "itertools 0.13.0", "num-traits", @@ -9625,23 +10453,22 @@ dependencies = [ "reth-storage-errors", "reth-trie", "reth-trie-db", - "thiserror", + "thiserror 1.0.69", "tokio", "tracing", ] [[package]] name = "reth-stages-api" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", "aquamarine", "auto_impl", "futures-util", "metrics", "reth-consensus", - "reth-db-api", "reth-errors", "reth-metrics", "reth-network-p2p", @@ -9652,17 +10479,18 @@ dependencies = [ "reth-static-file", "reth-static-file-types", "reth-tokio-util", - "thiserror", + "thiserror 1.0.69", "tokio", "tracing", ] [[package]] name = "reth-stages-types" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", + "arbitrary", "bytes", "modular-bitfield", "reth-codecs", @@ -9672,15 +10500,14 @@ dependencies = [ [[package]] name = "reth-static-file" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ - "alloy-primitives 0.8.0", - "parking_lot 0.12.3", + "alloy-primitives 0.8.12", + "parking_lot", "rayon", "reth-db", "reth-db-api", - "reth-nippy-jar", "reth-provider", "reth-prune-types", "reth-stages-types", @@ -9692,11 +10519,11 @@ dependencies = [ [[package]] name = "reth-static-file-types" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ - "alloy-primitives 0.8.0", - "clap 4.5.19", + "alloy-primitives 0.8.12", + "clap 4.5.21", "derive_more 1.0.0", "serde", "strum", @@ -9704,11 +10531,15 @@ dependencies = [ [[package]] name = "reth-storage-api" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives 0.8.12", "auto_impl", "reth-chainspec", + "reth-db-api", "reth-db-models", "reth-execution-types", "reth-primitives", @@ -9720,9 +10551,11 @@ dependencies = [ [[package]] name = "reth-storage-errors" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ + "alloy-eips", + "alloy-primitives 0.8.12", "alloy-rlp", "derive_more 1.0.0", "reth-fs-util", @@ -9731,8 +10564,8 @@ dependencies = [ [[package]] name = "reth-tasks" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ "auto_impl", "dyn-clone", @@ -9741,7 +10574,7 @@ dependencies = [ "pin-project", "rayon", "reth-metrics", - "thiserror", + "thiserror 1.0.69", "tokio", "tracing", "tracing-futures", @@ -9749,8 +10582,8 @@ dependencies = [ [[package]] name = "reth-tokio-util" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ "tokio", "tokio-stream", @@ -9759,10 +10592,10 @@ dependencies = [ [[package]] name = "reth-tracing" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ - "clap 4.5.19", + "clap 4.5.21", "eyre", "rolling-file", "tracing", @@ -9774,16 +10607,20 @@ dependencies = [ [[package]] name = "reth-transaction-pool" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives 0.8.12", "alloy-rlp", "aquamarine", "auto_impl", "bitflags 2.6.0", "futures-util", "metrics", - "parking_lot 0.12.3", + "parking_lot", + "rand 0.8.5", "reth-chain-state", "reth-chainspec", "reth-eth-wire-types", @@ -9798,7 +10635,7 @@ dependencies = [ "schnellru", "serde", "smallvec", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-stream", "tracing", @@ -9806,12 +10643,13 @@ dependencies = [ [[package]] name = "reth-trie" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ + "alloy-consensus", + "alloy-primitives 0.8.12", "alloy-rlp", "auto_impl", - "derive_more 1.0.0", "itertools 0.13.0", "metrics", "rayon", @@ -9822,18 +10660,20 @@ dependencies = [ "reth-storage-errors", "reth-trie-common", "revm", + "serde", + "serde_with", "tracing", "triehash", ] [[package]] name = "reth-trie-common" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ "alloy-consensus", "alloy-genesis", - "alloy-primitives 0.8.0", + "alloy-primitives 0.8.12", "alloy-rlp", "alloy-trie", "arbitrary", @@ -9851,57 +10691,54 @@ dependencies = [ [[package]] name = "reth-trie-db" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ + "alloy-primitives 0.8.12", "alloy-rlp", - "auto_impl", "derive_more 1.0.0", - "itertools 0.13.0", "metrics", - "rayon", "reth-db", "reth-db-api", "reth-execution-errors", "reth-metrics", "reth-primitives", - "reth-stages-types", "reth-storage-errors", "reth-trie", "reth-trie-common", "revm", + "serde", "tracing", + "triehash", ] [[package]] name = "reth-trie-parallel" -version = "1.0.6" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.0.6#c228fe15808c3acbf18dc3af1a03ef5cbdcda07a" +version = "1.1.1" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.1.1#15c230bac20e2b1b3532c8b0d470e815fbc0cc22" dependencies = [ + "alloy-primitives 0.8.12", "alloy-rlp", "derive_more 1.0.0", "itertools 0.13.0", "metrics", "rayon", "reth-db", - "reth-db-api", "reth-execution-errors", "reth-metrics", "reth-primitives", "reth-provider", - "reth-tasks", "reth-trie", "reth-trie-db", - "thiserror", - "tokio", + "thiserror 1.0.69", "tracing", ] [[package]] name = "revm" -version = "14.0.1" +version = "17.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f719e28cc6fdd086f8bc481429e587740d20ad89729cec3f5f5dd7b655474df" +checksum = "055bee6a81aaeee8c2389ae31f0d4de87f44df24f4444a1116f9755fd87a76ad" dependencies = [ "auto_impl", "cfg-if", @@ -9914,25 +10751,28 @@ dependencies = [ [[package]] name = "revm-inspectors" -version = "0.6.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48184032103bb23788e42e42c7c85207f5b0b8a248b09ea8f5233077f35ab56e" +checksum = "1e29c662f7887f3b659d4b0fd234673419a8fcbeaa1ecc29bf7034c0a75cc8ea" dependencies = [ - "alloy-primitives 0.8.0", - "alloy-rpc-types", + "alloy-primitives 0.8.12", + "alloy-rpc-types-eth", + "alloy-rpc-types-trace", "alloy-sol-types", "anstyle", + "boa_engine", + "boa_gc", "colorchoice", "revm", "serde_json", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "revm-interpreter" -version = "10.0.1" +version = "13.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "959ecbc36802de6126852479844737f20194cf8e6718e0c30697d306a2cca916" +checksum = "fac2034454f8bc69dc7d3c94cdb1b57559e27f5ef0518771f1787de543d7d6a1" dependencies = [ "revm-primitives", "serde", @@ -9940,15 +10780,15 @@ dependencies = [ [[package]] name = "revm-precompile" -version = "11.0.1" +version = "14.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e25f604cb9db593ca3013be8c00f310d6790ccb1b7d8fbbdd4660ec8888043a" +checksum = "7a88c8c7c5f9b988a9e65fc0990c6ce859cdb74114db705bd118a96d22d08027" dependencies = [ "aurora-engine-modexp", "blst", "c-kzg", "cfg-if", - "k256 0.13.3", + "k256 0.13.4", "once_cell", "p256", "revm-primitives", @@ -9960,12 +10800,13 @@ dependencies = [ [[package]] name = "revm-primitives" -version = "9.0.1" +version = "13.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ccb981ede47ccf87c68cebf1ba30cdbb7ec935233ea305f3dfff4c1e10ae541" +checksum = "0d11fa1e195b0bebaf3fb18596f314a13ba3a4cb1fdd16d3465934d812fd921e" dependencies = [ - "alloy-eips", - "alloy-primitives 0.8.0", + "alloy-eip2930", + "alloy-eip7702", + "alloy-primitives 0.8.12", "auto_impl", "bitflags 2.6.0", "bitvec", @@ -9973,7 +10814,6 @@ dependencies = [ "cfg-if", "dyn-clone", "enumn", - "hashbrown 0.14.5", "hex", "serde", ] @@ -10031,9 +10871,9 @@ dependencies = [ [[package]] name = "rlimit" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3560f70f30a0f16d11d01ed078a07740fe6b489667abc7c7b029155d9f21c3d8" +checksum = "7043b63bd0cd1aaa628e476b80e6d4023a3b50eb32789f2728908107bd0c793a" dependencies = [ "libc", ] @@ -10060,6 +10900,28 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "rmp" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "228ed7c16fa39782c3b3468e974aec2795e9089153cd08ee2e9aefb3613334c4" +dependencies = [ + "byteorder", + "num-traits", + "paste", +] + +[[package]] +name = "rmp-serde" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e599a477cf9840e92f2cde9a7189e67b42c57532749bf90aea6ec10facd4db" +dependencies = [ + "byteorder", + "rmp", + "serde", +] + [[package]] name = "roaring" version = "0.10.6" @@ -10153,6 +11015,9 @@ name = "rustc-hash" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" +dependencies = [ + "rand 0.8.5", +] [[package]] name = "rustc-hex" @@ -10171,18 +11036,18 @@ dependencies = [ [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver 1.0.23", ] [[package]] name = "rustix" -version = "0.38.34" +version = "0.38.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "99e4ea3e1cdc4b559b8e5650f9c8e5998e3e5c1343b4eaf034565f32318d63c0" dependencies = [ "bitflags 2.6.0", "errno", @@ -10205,15 +11070,15 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.12" +version = "0.23.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044" +checksum = "eee87ff5d9b36712a58574e12e9f0ea80f915a5b0ac518d322b24a465617925e" dependencies = [ "log", "once_cell", "ring", "rustls-pki-types", - "rustls-webpki 0.102.6", + "rustls-webpki 0.102.8", "subtle", "zeroize", ] @@ -10232,12 +11097,12 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.7.1" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a88d6d420651b496bdd98684116959239430022a115c1240e6c3993be0b15fba" +checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" dependencies = [ "openssl-probe", - "rustls-pemfile 2.1.2", + "rustls-pemfile 2.2.0", "rustls-pki-types", "schannel", "security-framework", @@ -10250,7 +11115,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcaf18a4f2be7326cd874a5fa579fae794320a0f388d365dca7e480e55f83f8a" dependencies = [ "openssl-probe", - "rustls-pemfile 2.1.2", + "rustls-pemfile 2.2.0", "rustls-pki-types", "schannel", "security-framework", @@ -10267,46 +11132,48 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "2.1.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" dependencies = [ - "base64 0.22.1", "rustls-pki-types", ] [[package]] name = "rustls-pki-types" -version = "1.7.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" +dependencies = [ + "web-time", +] [[package]] name = "rustls-platform-verifier" -version = "0.3.2" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e3beb939bcd33c269f4bf946cc829fcd336370267c4a927ac0399c84a3151a1" +checksum = "afbb878bdfdf63a336a5e63561b1835e7a8c91524f51621db870169eac84b490" dependencies = [ "core-foundation", "core-foundation-sys", "jni", "log", "once_cell", - "rustls 0.23.12", - "rustls-native-certs 0.7.1", + "rustls 0.23.16", + "rustls-native-certs 0.7.3", "rustls-platform-verifier-android", - "rustls-webpki 0.102.6", + "rustls-webpki 0.102.8", "security-framework", "security-framework-sys", - "webpki-roots 0.26.3", + "webpki-roots 0.26.6", "winapi", ] [[package]] name = "rustls-platform-verifier-android" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84e217e7fdc8466b5b35d30f8c0a30febd29173df4a3a0c2115d306b9c4117ad" +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" [[package]] name = "rustls-webpki" @@ -10320,9 +11187,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.102.6" +version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e6b52d4fda176fd835fdc55a835d4a89b8499cad995885a21149d5ad62f852e" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ "ring", "rustls-pki-types", @@ -10331,9 +11198,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" [[package]] name = "rusty-fork" @@ -10353,6 +11220,12 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +[[package]] +name = "ryu-js" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad97d4ce1560a5e27cec89519dc8300d1aa6035b099821261c651486a19e44d5" + [[package]] name = "same-file" version = "1.0.6" @@ -10364,35 +11237,35 @@ dependencies = [ [[package]] name = "scale-info" -version = "2.11.3" +version = "2.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca070c12893629e2cc820a9761bedf6ce1dcddc9852984d1dc734b8bd9bd024" +checksum = "1aa7ffc1c0ef49b0452c6e2986abf2b07743320641ffd5fc63d552458e3b779b" dependencies = [ "cfg-if", - "derive_more 0.99.18", + "derive_more 1.0.0", "parity-scale-codec", "scale-info-derive", ] [[package]] name = "scale-info-derive" -version = "2.11.3" +version = "2.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d35494501194174bda522a32605929eefc9ecf7e0a326c26db1fdd85881eb62" +checksum = "46385cc24172cf615450267463f937c10072516359b3ff1cb24228a4a08bf951" dependencies = [ - "proc-macro-crate 3.1.0", + "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.87", ] [[package]] name = "schannel" -version = "0.1.23" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -10475,9 +11348,9 @@ dependencies = [ [[package]] name = "secp256k1" -version = "0.29.0" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e0cc0f1cf93f4969faf3ea1c7d8a9faed25918d96affa959720823dfe86d4f3" +checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" dependencies = [ "rand 0.8.5", "secp256k1-sys", @@ -10486,9 +11359,9 @@ dependencies = [ [[package]] name = "secp256k1-sys" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1433bd67156263443f14d603720b082dd3121779323fce20cba2aa07b874bc1b" +checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9" dependencies = [ "cc", ] @@ -10509,9 +11382,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.11.1" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf" +checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2" dependencies = [ "core-foundation-sys", "libc", @@ -10583,40 +11456,31 @@ checksum = "a3f0bf26fd526d2a95683cd0f87bf103b8539e2ca1ef48ce002d67aad59aa0b4" [[package]] name = "serde" -version = "1.0.210" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] -[[package]] -name = "serde_bytes" -version = "0.11.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "387cc504cb06bb40a96c8e04e951fe01854cf6bc921053c954e4a606d9675c6a" -dependencies = [ - "serde", -] - [[package]] name = "serde_derive" -version = "1.0.210" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.87", ] [[package]] name = "serde_json" -version = "1.0.128" +version = "1.0.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" dependencies = [ - "indexmap 2.2.6", + "indexmap 2.6.0", "itoa", "memchr", "ryu", @@ -10631,14 +11495,25 @@ checksum = "c7715380eec75f029a4ef7de39a9200e0a63823176b759d055b613f5a87df6a6" dependencies = [ "percent-encoding", "serde", - "thiserror", + "thiserror 1.0.69", +] + +[[package]] +name = "serde_repr" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", ] [[package]] name = "serde_spanned" -version = "0.6.6" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" dependencies = [ "serde", ] @@ -10657,15 +11532,15 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.9.0" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cecfa94848272156ea67b2b1a53f20fc7bc638c4a46d2f8abde08f05f4b857" +checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" dependencies = [ "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.2.6", + "indexmap 2.6.0", "serde", "serde_derive", "serde_json", @@ -10675,14 +11550,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.9.0" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8fee4991ef4f274617a51ad4af30519438dacb2f56ac773b08a1922ff743350" +checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.87", ] [[package]] @@ -10772,9 +11647,9 @@ dependencies = [ [[package]] name = "sha3-asm" -version = "0.1.1" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9b57fd861253bff08bb1919e995f90ba8f4889de2726091c8876f3a4e823b40" +checksum = "c28efc5e327c837aa837c59eae585fc250715ef939ac32881bcc11677cd02d46" dependencies = [ "cc", "cfg-if", @@ -10816,12 +11691,12 @@ dependencies = [ [[package]] name = "signal-hook-mio" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" +checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd" dependencies = [ "libc", - "mio 0.8.11", + "mio 1.0.2", "signal-hook", ] @@ -10856,9 +11731,9 @@ dependencies = [ [[package]] name = "simdutf8" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" [[package]] name = "similar" @@ -10872,11 +11747,12 @@ dependencies = [ [[package]] name = "similar-asserts" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e041bb827d1bfca18f213411d51b665309f1afb37a04a5d1464530e13779fc0f" +checksum = "cfe85670573cd6f0fa97940f26e7e6601213c3b0555246c24234131f88c5709e" dependencies = [ "console", + "serde", "similar", ] @@ -10888,7 +11764,7 @@ checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" dependencies = [ "num-bigint", "num-traits", - "thiserror", + "thiserror 1.0.69", "time", ] @@ -10900,9 +11776,9 @@ checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" [[package]] name = "sketches-ddsketch" -version = "0.2.2" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85636c14b73d81f541e525f585c0a2109e6744e1565b5c1668e31c70c10ed65c" +checksum = "c1e9a774a6c28142ac54bb25d25562e6bcf957493a184f15ad4eebccb23e410a" [[package]] name = "slab" @@ -10940,16 +11816,6 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b6b67fb9a61334225b5b790716f609cd58395f895b3fe8b328786812a40bc3b" -[[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" @@ -11030,11 +11896,17 @@ dependencies = [ "der 0.7.9", ] +[[package]] +name = "sptr" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b9b39299b249ad65f3b7e96443bad61c02ca5cd3589f46cb6d610a0fd6c0d6a" + [[package]] name = "sqlformat" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f895e3734318cc55f1fe66258926c9b910c124d47520339efecbb6c59cec7c1f" +checksum = "7bba3a93db0cc4f7bdece8bb09e77e2e785c20bfebf79eb8340ed80708048790" dependencies = [ "nom", "unicode_categories", @@ -11083,9 +11955,9 @@ dependencies = [ "futures-intrusive", "futures-io", "futures-util", - "hashlink", + "hashlink 0.8.4", "hex", - "indexmap 2.2.6", + "indexmap 2.6.0", "log", "memchr", "native-tls", @@ -11097,7 +11969,7 @@ dependencies = [ "sha2 0.10.8", "smallvec", "sqlformat", - "thiserror", + "thiserror 1.0.69", "time", "tokio", "tokio-stream", @@ -11184,7 +12056,7 @@ dependencies = [ "smallvec", "sqlx-core", "stringprep", - "thiserror", + "thiserror 1.0.69", "time", "tracing", "uuid", @@ -11227,7 +12099,7 @@ dependencies = [ "smallvec", "sqlx-core", "stringprep", - "thiserror", + "thiserror 1.0.69", "time", "tracing", "uuid", @@ -11275,9 +12147,9 @@ dependencies = [ [[package]] name = "ssz_rs" version = "0.9.0" -source = "git+https://github.com/ralexstokes/ssz-rs.git#84ef2b71aa004f6767420badb42c902ad56b8b72" +source = "git+https://github.com/ralexstokes/ssz-rs.git#ec3073e2273b4d0873fcb6df68ff4eff79588e92" dependencies = [ - "alloy-primitives 0.7.7", + "alloy-primitives 0.8.12", "bitvec", "serde", "sha2 0.9.9", @@ -11297,23 +12169,13 @@ dependencies = [ [[package]] name = "ssz_rs_derive" version = "0.9.0" -source = "git+https://github.com/ralexstokes/ssz-rs.git#84ef2b71aa004f6767420badb42c902ad56b8b72" +source = "git+https://github.com/ralexstokes/ssz-rs.git#ec3073e2273b4d0873fcb6df68ff4eff79588e92" dependencies = [ "proc-macro2", "quote", "syn 1.0.109", ] -[[package]] -name = "stability" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d904e7009df136af5297832a3ace3370cd14ff1546a232f4f185036c2736fcac" -dependencies = [ - "quote", - "syn 2.0.72", -] - [[package]] name = "stable_deref_trait" version = "1.2.0" @@ -11355,7 +12217,7 @@ checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" dependencies = [ "new_debug_unreachable", "once_cell", - "parking_lot 0.12.3", + "parking_lot", "phf_shared 0.10.0", "precomputed-hash", "serde", @@ -11409,7 +12271,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.72", + "syn 2.0.87", ] [[package]] @@ -11422,7 +12284,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.72", + "syn 2.0.87", ] [[package]] @@ -11444,16 +12306,6 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" -[[package]] -name = "sucds" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53d46182afe6ed822a94c54a532dc0d59691a8f49226bdc4596529ca864cdd6" -dependencies = [ - "anyhow", - "num-traits", -] - [[package]] name = "syn" version = "1.0.109" @@ -11467,9 +12319,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.72" +version = "2.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" dependencies = [ "proc-macro2", "quote", @@ -11478,14 +12330,14 @@ dependencies = [ [[package]] name = "syn-solidity" -version = "0.8.0" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "284c41c2919303438fcf8dede4036fd1e82d4fc0fbb2b279bd2a1442c909ca92" +checksum = "f76fe0a3e1476bdaa0775b9aec5b869ed9520c2b2fedfe9c6df3618f8ea6290b" dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.87", ] [[package]] @@ -11515,6 +12367,17 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "sysinfo" version = "0.29.11" @@ -11531,16 +12394,15 @@ dependencies = [ [[package]] name = "sysinfo" -version = "0.30.13" +version = "0.31.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a5b4ddaee55fb2bea2bf0e5000747e5f5c0de765e5a5ff87f4cd106439f4bb3" +checksum = "355dbe4f8799b304b05e1b0f05fc59b2a18d36645cf169607da45bde2f69a1be" dependencies = [ - "cfg-if", "core-foundation-sys", "libc", + "memchr", "ntapi", - "once_cell", - "windows 0.52.0", + "windows 0.57.0", ] [[package]] @@ -11599,14 +12461,15 @@ checksum = "c1bbb9f3c5c463a01705937a24fdabc5047929ac764b2d5b9cf681c1f5041ed5" [[package]] name = "tempfile" -version = "3.10.1" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" dependencies = [ "cfg-if", - "fastrand 2.1.0", + "fastrand 2.2.0", + "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -11633,7 +12496,7 @@ dependencies = [ "proc-macro2", "quote", "reqwest 0.11.27", - "syn 2.0.72", + "syn 2.0.87", "which", ] @@ -11643,24 +12506,50 @@ version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" +[[package]] +name = "thin-vec" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a38c90d48152c236a3ab59271da4f4ae63d678c5d7ad6b7714d7cb9760be5e4b" + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + [[package]] name = "thiserror" -version = "1.0.64" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c006c85c7651b3cf2ada4584faa36773bd07bac24acfb39f3c431b36d7e667aa" +dependencies = [ + "thiserror-impl 2.0.3", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ - "thiserror-impl", + "proc-macro2", + "quote", + "syn 2.0.87", ] [[package]] name = "thiserror-impl" -version = "1.0.64" +version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" +checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.87", ] [[package]] @@ -11704,9 +12593,9 @@ dependencies = [ [[package]] name = "tikv-jemalloc-ctl" -version = "0.5.4" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "619bfed27d807b54f7f776b9430d4f8060e66ee138a28632ca898584d462c31c" +checksum = "f21f216790c8df74ce3ab25b534e0718da5a1916719771d3fec23315c99e468b" dependencies = [ "libc", "paste", @@ -11715,9 +12604,9 @@ dependencies = [ [[package]] name = "tikv-jemalloc-sys" -version = "0.5.4+5.3.0-patched" +version = "0.6.0+5.3.0-1-ge13ca993e8ccb9ba9847cc330696e02839f328f7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9402443cb8fd499b6f327e40565234ff34dbda27460c5b47db0db77443dd85d1" +checksum = "cd3c60906412afa9c2b5b5a48ca6a5abe5736aec9eb48ad05037a677e52e4e2d" dependencies = [ "cc", "libc", @@ -11725,9 +12614,9 @@ dependencies = [ [[package]] name = "tikv-jemallocator" -version = "0.5.4" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "965fe0c26be5c56c94e38ba547249074803efd52adfb66de62107d95aab3eaca" +checksum = "4cec5ff18518d81584f477e9bfdf957f5bb0979b0bac3af4ca30b5b3ae2d2865" dependencies = [ "libc", "tikv-jemalloc-sys", @@ -11741,6 +12630,7 @@ checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ "deranged", "itoa", + "js-sys", "libc", "num-conv", "num_threads", @@ -11775,6 +12665,16 @@ dependencies = [ "crunchy", ] +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + [[package]] name = "tinytemplate" version = "1.2.1" @@ -11802,18 +12702,18 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.40.0" +version = "1.41.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" +checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" dependencies = [ "backtrace", "bytes", "libc", - "mio 1.0.1", - "parking_lot 0.12.3", + "mio 1.0.2", + "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.7", + "socket2", "tokio-macros", "windows-sys 0.52.0", ] @@ -11826,7 +12726,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.87", ] [[package]] @@ -11855,7 +12755,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.12", + "rustls 0.23.16", "rustls-pki-types", "tokio", ] @@ -11886,18 +12786,18 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.23.1" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6989540ced10490aaf14e6bad2e3d33728a2813310a0c71d1574304c49631cd" +checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9" dependencies = [ "futures-util", "log", - "rustls 0.23.12", + "rustls 0.23.16", "rustls-pki-types", "tokio", "tokio-rustls 0.26.0", - "tungstenite 0.23.0", - "webpki-roots 0.26.3", + "tungstenite 0.24.0", + "webpki-roots 0.26.6", ] [[package]] @@ -11926,47 +12826,36 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.15" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac2caab0bf757388c6c0ae23b3293fdb463fee59434529014f85e3263b995c28" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.16", + "toml_edit", ] [[package]] name = "toml_datetime" -version = "0.6.6" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" -dependencies = [ - "indexmap 2.2.6", - "toml_datetime", - "winnow 0.5.40", -] - -[[package]] -name = "toml_edit" -version = "0.22.16" +version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "278f3d518e152219c994ce877758516bca5e118eaed6996192a774fb9fbf0788" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ - "indexmap 2.2.6", + "indexmap 2.6.0", "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.15", + "winnow", ] [[package]] @@ -11990,6 +12879,20 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper 0.1.2", + "tower-layer", + "tower-service", +] + [[package]] name = "tower-http" version = "0.5.2" @@ -12014,7 +12917,7 @@ dependencies = [ "pin-project-lite", "tokio", "tokio-util", - "tower", + "tower 0.4.13", "tower-layer", "tower-service", "tracing", @@ -12023,15 +12926,15 @@ dependencies = [ [[package]] name = "tower-layer" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" @@ -12052,7 +12955,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf" dependencies = [ "crossbeam-channel", - "thiserror", + "thiserror 1.0.69", "time", "tracing-subscriber", ] @@ -12065,7 +12968,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.87", ] [[package]] @@ -12112,9 +13015,9 @@ dependencies = [ [[package]] name = "tracing-logfmt" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22b8e455f6caa5212a102ec530bf86b8dc5a4c536299bffd84b238fed9119be7" +checksum = "6b1f47d22deb79c3f59fcf2a1f00f60cbdc05462bf17d1cd356c1fefa3f444bd" dependencies = [ "time", "tracing", @@ -12157,10 +13060,12 @@ dependencies = [ name = "transaction-pool-bundle-ext" version = "0.1.0" dependencies = [ + "alloy-eips", + "alloy-primitives 0.8.12", + "alloy-rpc-types-beacon", "reth", "reth-eth-wire-types", "reth-primitives", - "reth-rpc-types", "reth-transaction-pool", "tokio", ] @@ -12193,7 +13098,7 @@ dependencies = [ "once_cell", "rand 0.8.5", "smallvec", - "thiserror", + "thiserror 1.0.69", "tinyvec", "tokio", "tracing", @@ -12211,11 +13116,12 @@ dependencies = [ "ipconfig", "lru-cache", "once_cell", - "parking_lot 0.12.3", + "parking_lot", "rand 0.8.5", "resolv-conf", + "serde", "smallvec", - "thiserror", + "thiserror 1.0.69", "tokio", "tracing", "trust-dns-proto", @@ -12241,7 +13147,7 @@ dependencies = [ "log", "rand 0.8.5", "sha1", - "thiserror", + "thiserror 1.0.69", "url", "utf-8", ] @@ -12259,10 +13165,28 @@ dependencies = [ "httparse", "log", "rand 0.8.5", - "rustls 0.23.12", + "sha1", + "thiserror 1.0.69", + "utf-8", +] + +[[package]] +name = "tungstenite" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http 1.1.0", + "httparse", + "log", + "rand 0.8.5", + "rustls 0.23.16", "rustls-pki-types", "sha1", - "thiserror", + "thiserror 1.0.69", "utf-8", ] @@ -12284,9 +13208,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "ucd-trie" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" [[package]] name = "uint" @@ -12300,6 +13224,18 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "uint" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "909988d098b2f738727b161a106cfc7cab00c539c2687a8836f8e565976fb53e" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + [[package]] name = "unarray" version = "0.1.4" @@ -12308,45 +13244,42 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicase" -version = "2.7.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] +checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" [[package]] name = "unicode-bidi" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" +checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-normalization" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ "tinyvec", ] [[package]] name = "unicode-properties" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4259d9d4425d9f0661581b804cb85fe66a4c631cadd8f490d1c13a35d5d9291" +checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" [[package]] name = "unicode-segmentation" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-truncate" @@ -12356,20 +13289,26 @@ checksum = "b3644627a5af5fa321c95b9b235a72fd24cd29c648c2c379431e6628655627bf" dependencies = [ "itertools 0.13.0", "unicode-segmentation", - "unicode-width", + "unicode-width 0.1.14", ] [[package]] name = "unicode-width" -version = "0.1.13" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "unicode-width" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" +checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" [[package]] name = "unicode-xid" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "unicode_categories" @@ -12393,6 +13332,12 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6889a77d49f1f013504cec6bf97a2c730394adedaeb1deb5ea08949a50541105" +[[package]] +name = "unsigned-varint" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb066959b24b5196ae73cb057f45598450d2c5f71460e98c49b738086eff9c06" + [[package]] name = "untrusted" version = "0.9.0" @@ -12401,28 +13346,28 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "ureq" -version = "2.10.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72139d247e5f97a3eff96229a7ae85ead5328a39efe76f8bf5a06313d505b6ea" +checksum = "b74fc6b57825be3373f7054754755f03ac3a8f5d70015ccad699ba2029956f4a" dependencies = [ "base64 0.22.1", "flate2", "log", "once_cell", - "rustls 0.23.12", + "rustls 0.23.16", "rustls-pki-types", "url", - "webpki-roots 0.26.3", + "webpki-roots 0.26.6", ] [[package]] name = "url" -version = "2.5.2" +version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +checksum = "8d157f1b96d14500ffdc1f10ba712e780825526c03d9a49b4d0324b0d9113ada" dependencies = [ "form_urlencoded", - "idna 0.5.0", + "idna 1.0.3", "percent-encoding", "serde", ] @@ -12439,6 +13384,18 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "utf8parse" version = "0.2.2" @@ -12447,9 +13404,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" +checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" dependencies = [ "getrandom 0.2.15", "serde", @@ -12484,9 +13441,20 @@ dependencies = [ [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "visibility" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "d674d135b4a8c1d7e813e2f8d1c9a58308aee4a680323066025e53132218bd91" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] [[package]] name = "wait-timeout" @@ -12533,7 +13501,7 @@ dependencies = [ "futures-util", "headers", "http 0.2.12", - "hyper 0.14.30", + "hyper 0.14.31", "log", "mime", "mime_guess", @@ -12571,34 +13539,35 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.87", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.42" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" dependencies = [ "cfg-if", "js-sys", @@ -12608,9 +13577,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -12618,28 +13587,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.87", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" [[package]] name = "wasm-streams" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" +checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" dependencies = [ "futures-util", "js-sys", @@ -12648,11 +13617,35 @@ dependencies = [ "web-sys", ] +[[package]] +name = "wasmtimer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7ed9d8b15c7fb594d72bfb4b5a276f3d2029333cd93a932f376f5937f6f80ee" +dependencies = [ + "futures", + "js-sys", + "parking_lot", + "pin-utils", + "slab", + "wasm-bindgen", +] + [[package]] name = "web-sys" -version = "0.3.69" +version = "0.3.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" dependencies = [ "js-sys", "wasm-bindgen", @@ -12666,9 +13659,9 @@ checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "webpki-roots" -version = "0.26.3" +version = "0.26.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd7c23921eeb1713a4e851530e9b9756e4fb0e89978582942612524cf09f01cd" +checksum = "841c67bff177718f1d4dfefde8d8f0e78f9b6589319ba88312f567fc5841a958" dependencies = [ "rustls-pki-types", ] @@ -12687,11 +13680,11 @@ dependencies = [ [[package]] name = "whoami" -version = "1.5.1" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44ab49fad634e88f55bf8f9bb3abd2f27d7204172a112c7c9987e01c1c94ea9" +checksum = "372d5b87f58ec45c384ba03563b03544dc5fadc3983e434b286913f5b4a9bb6d" dependencies = [ - "redox_syscall 0.4.1", + "redox_syscall", "wasite", ] @@ -12719,11 +13712,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -12734,21 +13727,21 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" -version = "0.52.0" +version = "0.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" +checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143" dependencies = [ - "windows-core 0.52.0", + "windows-core 0.57.0", "windows-targets 0.52.6", ] [[package]] name = "windows" -version = "0.57.0" +version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143" +checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" dependencies = [ - "windows-core 0.57.0", + "windows-core 0.58.0", "windows-targets 0.52.6", ] @@ -12767,12 +13760,25 @@ version = "0.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" dependencies = [ - "windows-implement", - "windows-interface", + "windows-implement 0.57.0", + "windows-interface 0.57.0", "windows-result 0.1.2", "windows-targets 0.52.6", ] +[[package]] +name = "windows-core" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" +dependencies = [ + "windows-implement 0.58.0", + "windows-interface 0.58.0", + "windows-result 0.2.0", + "windows-strings", + "windows-targets 0.52.6", +] + [[package]] name = "windows-implement" version = "0.57.0" @@ -12781,7 +13787,18 @@ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.87", +] + +[[package]] +name = "windows-implement" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", ] [[package]] @@ -12792,7 +13809,18 @@ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.87", +] + +[[package]] +name = "windows-interface" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", ] [[package]] @@ -12852,6 +13880,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-targets" version = "0.48.5" @@ -12975,18 +14012,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.5.40" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" -dependencies = [ - "memchr", -] - -[[package]] -name = "winnow" -version = "0.6.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "557404e450152cd6795bb558bca69e43c585055f4606e3bcae5894fc6dac9ba0" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" dependencies = [ "memchr", ] @@ -13001,6 +14029,18 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + [[package]] name = "ws_stream_wasm" version = "0.7.4" @@ -13012,23 +14052,14 @@ dependencies = [ "js-sys", "log", "pharos", - "rustc_version 0.4.0", + "rustc_version 0.4.1", "send_wrapper 0.6.0", - "thiserror", + "thiserror 1.0.69", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", ] -[[package]] -name = "wyhash" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf6e163c25e3fac820b4b453185ea2dea3b6a3e0a721d4d23d75bd33734c295" -dependencies = [ - "rand_core 0.6.4", -] - [[package]] name = "wyz" version = "0.5.1" @@ -13040,9 +14071,9 @@ dependencies = [ [[package]] name = "xxhash-rust" -version = "0.8.11" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63658493314859b4dfdf3fb8c1defd61587839def09582db50b8a4e93afca6bb" +checksum = "6a5cbf750400958819fb6178eaa83bee5cd9c29a26a40cc241df8c70fdd46984" [[package]] name = "yaml-rust" @@ -13053,12 +14084,43 @@ dependencies = [ "linked-hash-map", ] +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" + +[[package]] +name = "yoke" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", + "synstructure 0.13.1", +] + [[package]] name = "zerocopy" version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ + "byteorder", "zerocopy-derive", ] @@ -13070,7 +14132,28 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.87", +] + +[[package]] +name = "zerofrom" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", + "synstructure 0.13.1", ] [[package]] @@ -13090,7 +14173,29 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.87", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", ] [[package]] @@ -13137,7 +14242,7 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" dependencies = [ - "zstd-safe 7.2.0", + "zstd-safe 7.2.1", ] [[package]] @@ -13162,18 +14267,18 @@ dependencies = [ [[package]] name = "zstd-safe" -version = "7.2.0" +version = "7.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa556e971e7b568dc775c136fc9de8c779b1c2fc3a63defaafadffdbd3181afa" +checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" dependencies = [ "zstd-sys", ] [[package]] name = "zstd-sys" -version = "2.0.12+zstd.1.5.6" +version = "2.0.13+zstd.1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a4e40c320c3cb459d9a9ff6de98cff88f4751ee9275d140e2be94a2b74e4c13" +checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" dependencies = [ "cc", "pkg-config", diff --git a/Cargo.toml b/Cargo.toml index a9474db6..fd9045e5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,99 +30,101 @@ version = "0.1.0" edition = "2021" [workspace.dependencies] -reth = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } -reth-chain-state = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } -reth-beacon-consensus = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } -reth-cli-util = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } -reth-db = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } -reth-db-api = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } -reth-db-common = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } -reth-errors = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } -reth-libmdbx = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } -reth-payload-builder = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } -reth-payload-primitives = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } -reth-node-api = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } -reth-node-builder = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } -reth-node-ethereum = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } -reth-trie = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } -reth-trie-parallel = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } -reth-transaction-pool = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } -reth-basic-payload-builder = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } -reth-node-core = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } -reth-consensus = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } -reth-optimism-consensus = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } -reth-auto-seal-consensus = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } -reth-primitives = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } -reth-provider = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6", features = ["test-utils"] } -reth-chainspec = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } -reth-execution-types = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } -reth-revm = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } -reth-evm = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } -reth-evm-ethereum = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } -reth-evm-optimism = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } -reth-rpc = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } -reth-tracing = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } -reth-rpc-types = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } -reth-rpc-types-compat = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } -reth-rpc-eth-api = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } -reth-rpc-eth-types = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } -reth-rpc-api-types = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } -reth-discv4 = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } -reth-discv5 = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } -reth-network = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } -reth-node-optimism = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } -reth-eth-wire-types = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } -reth-storage-api = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } -reth-optimism-rpc = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } -reth-optimism-payload-builder = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } -reth-optimism-chainspec = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } -reth-execution-errors = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } -reth-trie-db = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.6" } +reth = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-chain-state = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-beacon-consensus = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-cli-util = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-db = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-db-api = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-db-common = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-errors = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-libmdbx = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-payload-builder = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-node-api = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-node-builder = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-node-ethereum = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-trie = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-trie-parallel = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-basic-payload-builder = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-node-core = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-primitives = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-provider = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1", features = ["test-utils"] } +reth-chainspec = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-evm = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-evm-ethereum = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-execution-errors = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-trie-db = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-payload-primitives = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-transaction-pool = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-consensus = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-optimism-consensus = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-optimism-cli = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-optimism-forks = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-auto-seal-consensus = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-execution-types = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-revm = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-optimism-evm = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-rpc = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-tracing = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-rpc-types-compat = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-rpc-eth-api = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-rpc-eth-types = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-rpc-api-types = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-discv4 = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-discv5 = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-network = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-optimism-node = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-eth-wire-types = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-storage-api = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-optimism-rpc = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-optimism-payload-builder = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } +reth-optimism-chainspec = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.1" } -# version is copied from reth "v1.0.6" dependencies -revm = { version = "14.0.0", features = [ +# version is copied from reth "v1.1.1" dependencies +revm = { version = "17.0.0", features = [ "std", "secp256k1", "optional_balance_check", ], default-features = false } -revm-inspectors = "0.6" -revm-primitives = { version = "9.0.0", features = [ +revm-inspectors = "0.10.0" +revm-primitives = { version = "13.0.0", features = [ "std", ], default-features = false } -ethereum_ssz_derive = "0.7" -ethereum_ssz = "0.7" +ethereum_ssz_derive = "0.8" +ethereum_ssz = "0.8" -alloy-primitives = { version = "0.8.0", default-features = false } +alloy-primitives = { version = "0.8.9", default-features = false } alloy-rlp = "0.3.4" -alloy-chains = "0.1.23" -alloy-provider = { version = "0.3.0", features = ["ipc", "pubsub"] } -alloy-pubsub = { version = "0.3.0" } -alloy-eips = { version = "0.3.6" } -alloy-rpc-types = { version = "0.3.0" } -alloy-json-rpc = { version = "0.3.0" } -alloy-transport-http = { version = "0.3.0" } -alloy-network = { version = "0.3.0" } -alloy-transport = { version = "0.3.0" } -alloy-node-bindings = { version = "0.3.0" } -alloy-consensus = { version = "0.3.0", features = ["kzg"] } -alloy-serde = { version = "0.3.0" } -alloy-rpc-types-beacon = { version = "0.3.6", features = [ +alloy-chains = "0.1.33" +alloy-provider = { version = "0.5.4", features = ["ipc", "pubsub"] } +alloy-pubsub = { version = "0.5.4" } +alloy-eips = { version = "0.5.4" } +alloy-rpc-types = { version = "0.5.4" } +alloy-json-rpc = { version = "0.5.4" } +alloy-transport-http = { version = "0.5.4" } +alloy-network = { version = "0.5.4" } +alloy-transport = { version = "0.5.4" } +alloy-node-bindings = { version = "0.5.4" } +alloy-consensus = { version = "0.5.4", features = ["kzg"] } +op-alloy-consensus = { version = "0.5.2", features = ["kzg"] } +alloy-serde = { version = "0.5.4" } +alloy-rpc-types-beacon = { version = "0.5.4", features = [ "ssz", ] } -alloy-rpc-types-engine = { version = "0.3.0", features = [ +alloy-rpc-types-engine = { version = "0.5.4", features = [ "ssz", ] } -alloy-rpc-types-eth = { version = "0.3.0" } -alloy-signer-local = { version = "0.3.0" } -alloy-genesis = { version = "0.3.0" } -alloy-trie = { version = "0.5.0" } +alloy-rpc-types-eth = { version = "0.5.4" } +alloy-signer-local = { version = "0.5.4" } +alloy-genesis = { version = "0.5.4" } +alloy-trie = { version = "0.7" } + async-trait = { version = "0.1.83" } clap = { version = "4.4.3" } thiserror = { version = "1.0.64" } eyre = { version = "0.6.12" } -tracing = { version = "0.1.37" } jsonrpsee = { version = "0.24.4" } jsonrpsee-types = { version = "0.24.4" } parking_lot = { version = "0.12.3" } @@ -138,7 +140,8 @@ tokio-util = "0.7.12" url = "2.5.2" libc = { version = "0.2.161" } -tikv-jemallocator = { version = "0.5.4" } +tikv-jemallocator = { version = "0.6" } +tracing = "0.1.37" eth-sparse-mpt = { path = "crates/eth-sparse-mpt" } diff --git a/crates/eth-sparse-mpt/benches/trie_insert_bench.rs b/crates/eth-sparse-mpt/benches/trie_insert_bench.rs index ae8bc8dd..6a4d1816 100644 --- a/crates/eth-sparse-mpt/benches/trie_insert_bench.rs +++ b/crates/eth-sparse-mpt/benches/trie_insert_bench.rs @@ -1,12 +1,13 @@ -use alloy_primitives::hex_literal::hex; -use alloy_primitives::Bytes; +use alloy_primitives::{hex_literal::hex, Bytes}; use criterion::{black_box, criterion_group, criterion_main, BatchSize, Criterion}; -use eth_sparse_mpt::reth_sparse_trie::change_set::ETHTrieChangeSet; -use eth_sparse_mpt::reth_sparse_trie::hash::EthSparseTries; -use eth_sparse_mpt::reth_sparse_trie::shared_cache::RethSparseTrieShareCacheInternal; -use eth_sparse_mpt::reth_sparse_trie::SparseTrieSharedCache; -use eth_sparse_mpt::sparse_mpt::{DiffTrie, FixedTrie}; -use eth_sparse_mpt::utils::{get_test_change_set, get_test_mutliproofs}; +use eth_sparse_mpt::{ + reth_sparse_trie::{ + change_set::ETHTrieChangeSet, hash::EthSparseTries, + shared_cache::RethSparseTrieShareCacheInternal, SparseTrieSharedCache, + }, + sparse_mpt::{DiffTrie, FixedTrie}, + utils::{get_test_change_set, get_test_mutliproofs}, +}; fn get_storage_tries(changes: ÐTrieChangeSet, tries: &EthSparseTries) -> Vec { let mut storage_tries = Vec::new(); diff --git a/crates/eth-sparse-mpt/benches/trie_nodes_benches.rs b/crates/eth-sparse-mpt/benches/trie_nodes_benches.rs index 77db7b20..84c97bb8 100644 --- a/crates/eth-sparse-mpt/benches/trie_nodes_benches.rs +++ b/crates/eth-sparse-mpt/benches/trie_nodes_benches.rs @@ -1,8 +1,10 @@ use alloy_primitives::{keccak256, Bytes, B256, U256}; use alloy_rlp::Encodable; use criterion::{black_box, criterion_group, criterion_main, Criterion}; -use eth_sparse_mpt::sparse_mpt::DiffTrie; -use eth_sparse_mpt::utils::{HashMap, KeccakHasher}; +use eth_sparse_mpt::{ + sparse_mpt::DiffTrie, + utils::{HashMap, KeccakHasher}, +}; // hashing this trie it roughly equivalent to updating the trie for the block const TRIE_SIZE: usize = 3000; diff --git a/crates/eth-sparse-mpt/src/reth_sparse_trie/hash.rs b/crates/eth-sparse-mpt/src/reth_sparse_trie/hash.rs index 5f316a6d..1f30b0b3 100644 --- a/crates/eth-sparse-mpt/src/reth_sparse_trie/hash.rs +++ b/crates/eth-sparse-mpt/src/reth_sparse_trie/hash.rs @@ -1,6 +1,8 @@ use super::change_set::ETHTrieChangeSet; -use crate::sparse_mpt::{DeletionError, DiffTrie, ErrSparseNodeNotFound}; -use crate::utils::HashMap; +use crate::{ + sparse_mpt::{DeletionError, DiffTrie, ErrSparseNodeNotFound}, + utils::HashMap, +}; use alloy_primitives::{Bytes, B256}; use alloy_rlp::Encodable; use rayon::prelude::*; diff --git a/crates/eth-sparse-mpt/src/reth_sparse_trie/mod.rs b/crates/eth-sparse-mpt/src/reth_sparse_trie/mod.rs index add84d02..5f56ea52 100644 --- a/crates/eth-sparse-mpt/src/reth_sparse_trie/mod.rs +++ b/crates/eth-sparse-mpt/src/reth_sparse_trie/mod.rs @@ -1,13 +1,10 @@ use alloy_primitives::{Address, B256}; -use change_set::prepare_change_set; -use change_set::prepare_change_set_for_prefetch; +use change_set::{prepare_change_set, prepare_change_set_for_prefetch}; use hash::RootHashError; -use reth_db_api::database::Database; -use reth_provider::providers::ConsistentDbView; -use reth_provider::DatabaseProviderFactory; -use reth_provider::ExecutionOutcome; -use std::time::Duration; -use std::time::Instant; +use reth_provider::{ + providers::ConsistentDbView, BlockReader, DatabaseProviderFactory, ExecutionOutcome, +}; +use std::time::{Duration, Instant}; pub mod change_set; pub mod hash; @@ -65,14 +62,13 @@ impl ChangedAccountData { } /// Prefetches data -pub fn prefetch_tries_for_accounts<'a, DB, Provider>( - consistent_db_view: ConsistentDbView, +pub fn prefetch_tries_for_accounts<'a, Provider>( + consistent_db_view: ConsistentDbView, shared_cache: SparseTrieSharedCache, changed_data: impl Iterator, ) -> Result<(), SparseTrieError> where - DB: Database, - Provider: DatabaseProviderFactory + Send + Sync, + Provider: DatabaseProviderFactory + Send + Sync, { let change_set = prepare_change_set_for_prefetch(changed_data); @@ -95,14 +91,13 @@ where /// Calculate root hash for the given outcome on top of the block defined by consistent_db_view. /// * shared_cache should be created once for each parent block and it stores fethed parts of the trie /// * It uses rayon for parallelism and the thread pool should be configured from outside. -pub fn calculate_root_hash_with_sparse_trie( - consistent_db_view: ConsistentDbView, +pub fn calculate_root_hash_with_sparse_trie( + consistent_db_view: ConsistentDbView, outcome: &ExecutionOutcome, shared_cache: SparseTrieSharedCache, ) -> (Result, SparseTrieMetrics) where - DB: Database, - Provider: DatabaseProviderFactory + Send + Sync, + Provider: DatabaseProviderFactory + Send + Sync, { let mut metrics = SparseTrieMetrics::default(); diff --git a/crates/eth-sparse-mpt/src/reth_sparse_trie/shared_cache.rs b/crates/eth-sparse-mpt/src/reth_sparse_trie/shared_cache.rs index 414d0f30..ca3eb4f4 100644 --- a/crates/eth-sparse-mpt/src/reth_sparse_trie/shared_cache.rs +++ b/crates/eth-sparse-mpt/src/reth_sparse_trie/shared_cache.rs @@ -1,10 +1,10 @@ use std::sync::{Arc, RwLock}; -use super::change_set::ETHTrieChangeSet; -use super::hash::EthSparseTries; -use super::trie_fetcher::MultiProof; -use crate::sparse_mpt::{AddNodeError, FixedTrie}; -use crate::utils::HashMap; +use super::{change_set::ETHTrieChangeSet, hash::EthSparseTries, trie_fetcher::MultiProof}; +use crate::{ + sparse_mpt::{AddNodeError, FixedTrie}, + utils::HashMap, +}; use alloy_primitives::Bytes; use alloy_trie::Nibbles; diff --git a/crates/eth-sparse-mpt/src/reth_sparse_trie/trie_fetcher/mod.rs b/crates/eth-sparse-mpt/src/reth_sparse_trie/trie_fetcher/mod.rs index e1dc418f..c8a0b66f 100644 --- a/crates/eth-sparse-mpt/src/reth_sparse_trie/trie_fetcher/mod.rs +++ b/crates/eth-sparse-mpt/src/reth_sparse_trie/trie_fetcher/mod.rs @@ -1,18 +1,18 @@ use crate::utils::{hash_map_with_capacity, HashMap, HashSet}; +use alloy_primitives::map::{HashMap as AlloyHashMap, HashSet as AlloyHashSet}; + use alloy_primitives::{Bytes, B256}; use alloy_trie::Nibbles; use rayon::prelude::*; -use reth_db_api::database::Database; use reth_errors::ProviderError; use reth_execution_errors::trie::StateProofError; -use reth_provider::providers::ConsistentDbView; -use reth_provider::DatabaseProviderFactory; -use reth_trie::proof::Proof; -use reth_trie::{MultiProof as RethMultiProof, EMPTY_ROOT_HASH}; +use reth_provider::{ + providers::ConsistentDbView, BlockReader, DBProvider, DatabaseProviderFactory, +}; +use reth_trie::{proof::Proof, MultiProof as RethMultiProof, EMPTY_ROOT_HASH}; use reth_trie_db::{DatabaseHashedCursorFactory, DatabaseTrieCursorFactory}; use serde::{Deserialize, Serialize}; use serde_with::{serde_as, Seq}; -use std::collections::HashMap as StdHashMap; use super::shared_cache::MissingNodes; @@ -51,16 +51,15 @@ pub struct StorageMultiProof { } #[derive(Debug)] -pub struct TrieFetcher { - consistent_db_view: ConsistentDbView, +pub struct TrieFetcher { + consistent_db_view: ConsistentDbView, } -impl TrieFetcher +impl TrieFetcher where - DB: Database, - Provider: DatabaseProviderFactory + Send + Sync, + Provider: DatabaseProviderFactory + Send + Sync, { - pub fn new(consistent_db_view: ConsistentDbView) -> Self { + pub fn new(consistent_db_view: ConsistentDbView) -> Self { Self { consistent_db_view } } @@ -74,13 +73,12 @@ where .into_par_iter() .map(|targets| -> Result { let provider = self.consistent_db_view.provider_ro()?; - let proof = Proof::new( DatabaseTrieCursorFactory::new(provider.tx_ref()), DatabaseHashedCursorFactory::new(provider.tx_ref()), ); - let reth_multiproof = proof.with_targets(targets).multiproof()?; + let reth_multiproof = proof.multiproof(targets)?; let result = convert_reth_multiproof(reth_multiproof, &all_requested_accounts); Ok(result) }) @@ -103,7 +101,7 @@ fn pad_path(mut path: Nibbles) -> B256 { fn get_proof_targets( missing_nodes: MissingNodes, -) -> (Vec>>, HashSet) { +) -> (Vec>>, HashSet) { // we will split all missing nodes accounts into buckets of (missing accounts / account_per_fetch) let account_per_fetch = 5; @@ -115,7 +113,7 @@ fn get_proof_targets( if is_address { all_requested_accounts.insert(hashed_address); } - targets.insert(hashed_address, Vec::new()); + targets.insert(hashed_address, AlloyHashSet::default()); } for (account, missing_storage_nodes) in missing_nodes.storage_trie_nodes { let hashed_address = B256::from_slice(&account); @@ -123,14 +121,14 @@ fn get_proof_targets( let storage_targets = targets.entry(hashed_address).or_default(); for node in missing_storage_nodes { let node = pad_path(node); - storage_targets.push(node); + storage_targets.insert(node); } } - let mut result = Vec::new(); + let mut result = Vec::>>::new(); let mut iter = targets.into_iter(); loop { - let mut split_target = StdHashMap::new(); + let mut split_target = AlloyHashMap::>::default(); let mut count = 0; for (target_key, target_value) in iter.by_ref() { split_target.insert(target_key, target_value); @@ -182,7 +180,7 @@ fn convert_reth_multiproof( all_requested_accounts: &HashSet, ) -> MultiProof { let mut account_subtree = Vec::with_capacity(reth_proof.account_subtree.len()); - for (k, v) in reth_proof.account_subtree { + for (k, v) in reth_proof.account_subtree.into_inner() { account_subtree.push((k, v)); } account_subtree.sort_by_key(|a| a.0.clone()); @@ -196,7 +194,7 @@ fn convert_reth_multiproof( } let mut subtree = Vec::with_capacity(reth_storage_proof.subtree.len()); - for (k, v) in reth_storage_proof.subtree { + for (k, v) in reth_storage_proof.subtree.into_inner() { subtree.push((k, v)); } subtree.sort_by_key(|a| a.0.clone()); diff --git a/crates/eth-sparse-mpt/src/sparse_mpt/diff_trie/mod.rs b/crates/eth-sparse-mpt/src/sparse_mpt/diff_trie/mod.rs index 5a0b3732..92007b0e 100644 --- a/crates/eth-sparse-mpt/src/sparse_mpt/diff_trie/mod.rs +++ b/crates/eth-sparse-mpt/src/sparse_mpt/diff_trie/mod.rs @@ -1,5 +1,4 @@ -use crate::utils::{extract_prefix_and_suffix, strip_first_nibble_mut}; -use crate::utils::{rlp_pointer, HashMap}; +use crate::utils::{extract_prefix_and_suffix, rlp_pointer, strip_first_nibble_mut, HashMap}; use alloy_primitives::{keccak256, Bytes, B256}; use reth_trie::Nibbles; use serde::{Deserialize, Serialize}; @@ -329,7 +328,7 @@ impl DiffTrie { let mut other_child_path = c.current_path.clone(); if let Some(l) = other_child_path.as_mut_vec_unchecked().last_mut() { *l = other_child_nibble; - }; + } return Err(DeletionError::NodeNotFound(ErrSparseNodeNotFound { path: other_child_path, ptr: u64::MAX, @@ -651,21 +650,14 @@ impl DiffTrie { } } } - - #[allow(clippy::while_let_loop)] - loop { - let wait = if let Some(w) = wait_stack.last() { - if result_stack.len() < w.need_elements + w.stack_before { - break; - } - wait_stack.pop().unwrap() - } else { + while let Some(w) = wait_stack.last() { + if result_stack.len() < w.need_elements + w.stack_before { break; - }; + } + let wait = wait_stack.pop().unwrap(); let node = try_get_node_mut(&mut self.nodes, wait.node, &empty_path)?; let idx = result_stack.len() - wait.need_elements; update_node_with_calculated_dirty_children(node, result_stack.drain(idx..).rev()); - result_stack.push(node.rlp_pointer_slow()); } } diff --git a/crates/eth-sparse-mpt/src/sparse_mpt/diff_trie/tests.rs b/crates/eth-sparse-mpt/src/sparse_mpt/diff_trie/tests.rs index 0520b577..c8d33bda 100644 --- a/crates/eth-sparse-mpt/src/sparse_mpt/diff_trie/tests.rs +++ b/crates/eth-sparse-mpt/src/sparse_mpt/diff_trie/tests.rs @@ -1,13 +1,12 @@ use super::*; -use crate::sparse_mpt::*; -use crate::utils::reference_trie_hash; -use crate::utils::HashSet; -use crate::utils::StoredFailureCase; +use crate::{ + sparse_mpt::*, + utils::{reference_trie_hash, HashSet, StoredFailureCase}, +}; use alloy_primitives::{Bytes, B256}; use eyre::Context; use proptest::prelude::*; -use rand::seq::SliceRandom; -use rand::SeedableRng; +use rand::{seq::SliceRandom, SeedableRng}; fn convert_input_to_bytes(input: &[(Vec, Vec)]) -> Vec<(Bytes, Bytes)> { input diff --git a/crates/eth-sparse-mpt/src/sparse_mpt/fixed_trie.rs b/crates/eth-sparse-mpt/src/sparse_mpt/fixed_trie.rs index b11c900b..67a148a7 100644 --- a/crates/eth-sparse-mpt/src/sparse_mpt/fixed_trie.rs +++ b/crates/eth-sparse-mpt/src/sparse_mpt/fixed_trie.rs @@ -1,6 +1,4 @@ -use crate::utils::hash_map_with_capacity; -use crate::utils::HashMap; -use crate::utils::HashSet; +use crate::utils::{hash_map_with_capacity, HashMap, HashSet}; use alloy_primitives::Bytes; use alloy_rlp::Decodable; use alloy_trie::nodes::{ @@ -11,16 +9,13 @@ use reth_trie::Nibbles; use serde::{Deserialize, Serialize}; use serde_with::{serde_as, Seq}; use smallvec::SmallVec; -use std::cmp::max; -use std::sync::Arc; +use std::{cmp::max, sync::Arc}; use crate::utils::strip_first_nibble_mut; -use super::get_new_ptr; -use super::NodeCursor; use super::{ - DiffBranchNode, DiffChildPtr, DiffExtensionNode, DiffLeafNode, DiffTrie, DiffTrieNode, - DiffTrieNodeKind, + get_new_ptr, DiffBranchNode, DiffChildPtr, DiffExtensionNode, DiffLeafNode, DiffTrie, + DiffTrieNode, DiffTrieNodeKind, NodeCursor, }; #[derive(Debug, Clone, Serialize, Deserialize)] @@ -111,7 +106,8 @@ impl From for FixedBranchNode { let rlp_data = stack_iter .next() .expect("stack must be the same size as mask"); - children[index as usize] = Some(rlp_data.into()); + // @Pending: Eval replacing Bytes for ArrayVec to avoid the copy or dig deeper into low-level. + children[index as usize] = Some(Bytes::copy_from_slice(rlp_data.as_ref())); child_mask |= 1 << index } } @@ -132,7 +128,7 @@ impl From for FixedExtensionNode { fn from(alloy_extension_node: AlloyExtensionNode) -> Self { Self { key: alloy_extension_node.key, - child: alloy_extension_node.child.into(), + child: Bytes::copy_from_slice(alloy_extension_node.child.as_ref()), } } } @@ -234,6 +230,7 @@ impl FixedTrie { child_ptr: None, }, AlloyTrieNode::Leaf(node) => FixedTrieNode::Leaf(Arc::new(node.into())), + AlloyTrieNode::EmptyRoot => FixedTrieNode::Null, }; // here we find parent to link with this new node diff --git a/crates/eth-sparse-mpt/src/utils.rs b/crates/eth-sparse-mpt/src/utils.rs index 066e8f82..d184fc6f 100644 --- a/crates/eth-sparse-mpt/src/utils.rs +++ b/crates/eth-sparse-mpt/src/utils.rs @@ -1,14 +1,17 @@ use alloy_primitives::{keccak256, Bytes, B256}; use alloy_rlp::{length_of_length, BufMut, Encodable, Header, EMPTY_STRING_CODE}; -use alloy_trie::nodes::{ExtensionNodeRef, LeafNodeRef}; -use alloy_trie::Nibbles; -use reth_trie::word_rlp; +use alloy_trie::{ + nodes::{ExtensionNodeRef, LeafNodeRef}, + Nibbles, +}; +use reth_trie::RlpNode; use rustc_hash::{FxBuildHasher, FxHasher}; use serde::{Deserialize, Serialize}; -use crate::reth_sparse_trie::change_set::ETHTrieChangeSet; -use crate::reth_sparse_trie::trie_fetcher::MultiProof; -use crate::sparse_mpt::DiffTrie; +use crate::{ + reth_sparse_trie::{change_set::ETHTrieChangeSet, trie_fetcher::MultiProof}, + sparse_mpt::DiffTrie, +}; pub type HashMap = std::collections::HashMap; pub type HashSet = std::collections::HashSet; @@ -21,7 +24,7 @@ pub fn rlp_pointer(rlp_encode: Bytes) -> Bytes { if rlp_encode.len() < 32 { rlp_encode } else { - word_rlp(&keccak256(&rlp_encode)).into() + Bytes::copy_from_slice(RlpNode::word_rlp(&keccak256(&rlp_encode)).as_ref()) } } diff --git a/crates/op-rbuilder/Cargo.toml b/crates/op-rbuilder/Cargo.toml index c75a6f0f..48ce3d66 100644 --- a/crates/op-rbuilder/Cargo.toml +++ b/crates/op-rbuilder/Cargo.toml @@ -9,9 +9,9 @@ op-rbuilder-node-optimism = { path = "./node" } transaction-pool-bundle-ext = { path = "../transaction-pool-bundle-ext" } reth.workspace = true -reth-node-optimism.workspace = true +reth-optimism-node.workspace = true +reth-optimism-cli.workspace = true reth-cli-util.workspace = true -reth-optimism-rpc.workspace = true tokio.workspace = true tracing.workspace = true @@ -20,7 +20,7 @@ async-trait = { workspace = true } clap_builder = { workspace = true } [target.'cfg(unix)'.dependencies] -tikv-jemallocator = { version = "0.5.0", optional = true } +tikv-jemallocator = { version = "0.6", optional = true } [dev-dependencies] reth-discv4.workspace = true @@ -28,11 +28,16 @@ reth-discv4.workspace = true [features] default = ["jemalloc"] -jemalloc = ["dep:tikv-jemallocator"] +jemalloc = [ + "dep:tikv-jemallocator", + "reth-cli-util/jemalloc", + "reth-optimism-cli/jemalloc" +] jemalloc-prof = [ "jemalloc", "tikv-jemallocator?/profiling", - "reth/jemalloc-prof" + "reth/jemalloc-prof", + "reth-cli-util/jemalloc-prof" ] min-error-logs = ["tracing/release_max_level_error"] @@ -42,11 +47,10 @@ min-debug-logs = ["tracing/release_max_level_debug"] min-trace-logs = ["tracing/release_max_level_trace"] optimism = [ - "reth-node-optimism/optimism", - "reth/optimism", - "reth-optimism-rpc/optimism", + "rbuilder/optimism", + "reth-optimism-node/optimism", "op-rbuilder-node-optimism/optimism", - "rbuilder/optimism" + "reth-optimism-cli/optimism" ] redact-sensitive = [ diff --git a/crates/op-rbuilder/node/Cargo.toml b/crates/op-rbuilder/node/Cargo.toml index 350dc79d..8ec3d539 100644 --- a/crates/op-rbuilder/node/Cargo.toml +++ b/crates/op-rbuilder/node/Cargo.toml @@ -9,17 +9,19 @@ transaction-pool-bundle-ext = { path = "../../transaction-pool-bundle-ext" } rbuilder-bundle-pool-operations = { path = "../../transaction-pool-bundle-ext/bundle_pool_ops/rbuilder" } # reth -reth-chainspec.workspace = true reth-payload-builder.workspace = true reth-primitives.workspace = true reth-basic-payload-builder.workspace = true reth-node-builder.workspace = true +reth-node-api.workspace = true +reth-trie-db.workspace = true reth-tracing.workspace = true reth-provider.workspace = true reth-transaction-pool.workspace = true reth-evm.workspace = true -reth-evm-optimism.workspace = true -reth-node-optimism = { workspace = true } +reth-optimism-evm.workspace = true +reth-optimism-chainspec.workspace = true +reth-optimism-node = { workspace = true } # async tracing.workspace = true @@ -30,11 +32,10 @@ eyre.workspace = true [features] optimism = [ - "reth-node-optimism/optimism", - "reth-chainspec/optimism", - "reth-provider/optimism", - "reth-evm-optimism/optimism", - "op-rbuilder-payload-builder/optimism", "rbuilder-bundle-pool-operations/optimism", - "reth-primitives/optimism" + "reth-optimism-evm/optimism", + "reth-optimism-node/optimism", + "reth-primitives/optimism", + "reth-provider/optimism", + "op-rbuilder-payload-builder/optimism" ] diff --git a/crates/op-rbuilder/node/src/args.rs b/crates/op-rbuilder/node/src/args.rs index c0ea455a..16f3c67b 100644 --- a/crates/op-rbuilder/node/src/args.rs +++ b/crates/op-rbuilder/node/src/args.rs @@ -6,6 +6,10 @@ use std::path::PathBuf; +use reth_node_builder::engine_tree_config::{ + DEFAULT_MEMORY_BLOCK_BUFFER_TARGET, DEFAULT_PERSISTENCE_THRESHOLD, +}; + /// Parameters for rollup configuration #[derive(Debug, Clone, Default, PartialEq, Eq, clap::Args)] #[command(next_help_heading = "Rollup")] @@ -38,10 +42,25 @@ pub struct OpRbuilderArgs { #[arg(long = "rollup.discovery.v4", default_value = "false")] pub discovery_v4: bool, - /// Enable the engine2 experimental features on op-reth binary + /// Enable the experimental engine features on reth binary + /// + /// DEPRECATED: experimental engine is default now, use --engine.legacy to enable the legacy + /// functionality #[arg(long = "engine.experimental", default_value = "false")] pub experimental: bool, + /// Enable the legacy engine on reth binary + #[arg(long = "engine.legacy", default_value = "false")] + pub legacy: bool, + + /// Configure persistence threshold for engine experimental. + #[arg(long = "engine.persistence-threshold", conflicts_with = "legacy", default_value_t = DEFAULT_PERSISTENCE_THRESHOLD)] + pub persistence_threshold: u64, + + /// Configure the target number of blocks to keep in memory. + #[arg(long = "engine.memory-block-buffer-target", conflicts_with = "legacy", default_value_t = DEFAULT_MEMORY_BLOCK_BUFFER_TARGET)] + pub memory_block_buffer_target: u64, + /// Enable the engine2 experimental features on op-reth binary #[arg(long = "rbuilder.config")] pub rbuilder_config_path: PathBuf, diff --git a/crates/op-rbuilder/node/src/node.rs b/crates/op-rbuilder/node/src/node.rs index 47ce9c8f..4e24cb8e 100644 --- a/crates/op-rbuilder/node/src/node.rs +++ b/crates/op-rbuilder/node/src/node.rs @@ -5,37 +5,46 @@ use rbuilder_bundle_pool_operations::BundlePoolOps; use reth_basic_payload_builder::{BasicPayloadJobGenerator, BasicPayloadJobGeneratorConfig}; -use reth_chainspec::ChainSpec; use reth_evm::ConfigureEvm; -use reth_evm_optimism::OptimismEvmConfig; +use reth_node_api::NodePrimitives; use reth_node_builder::{ components::{ComponentsBuilder, PayloadServiceBuilder, PoolBuilder}, node::{FullNodeTypes, NodeTypes}, - BuilderContext, Node, PayloadBuilderConfig, + BuilderContext, Node, NodeAdapter, NodeComponentsBuilder, NodeTypesWithEngine, + PayloadBuilderConfig, }; -use reth_node_optimism::{ - node::{ - OptimismAddOns, OptimismConsensusBuilder, OptimismExecutorBuilder, OptimismNetworkBuilder, - }, +use reth_optimism_chainspec::OpChainSpec; +use reth_optimism_evm::OpEvmConfig; +use reth_optimism_node::{ + node::{OpConsensusBuilder, OpExecutorBuilder, OpNetworkBuilder, OpPrimitives, OptimismAddOns}, txpool::OpTransactionValidator, - OptimismEngineTypes, + OpEngineTypes, }; use reth_payload_builder::{PayloadBuilderHandle, PayloadBuilderService}; -use reth_primitives::TransactionSigned; -use reth_provider::CanonStateSubscriptions; +use reth_primitives::{Header, TransactionSigned}; +use reth_provider::{BlockReader, CanonStateSubscriptions, DatabaseProviderFactory}; use reth_tracing::tracing::{debug, info}; use reth_transaction_pool::{ blobstore::DiskFileBlobStore, CoinbaseTipOrdering, EthPooledTransaction, TransactionValidationTaskExecutor, }; -use std::path::PathBuf; +use reth_trie_db::MerklePatriciaTrie; +use std::{path::PathBuf, sync::Arc}; use transaction_pool_bundle_ext::{ BundlePoolOperations, BundleSupportedPool, TransactionPoolBundleExt, }; use crate::args::OpRbuilderArgs; -/// Type configuration for an OP rbuilder node. +/// Optimism primitive types. +#[derive(Debug)] +pub struct OpRbuilderPrimitives; + +impl NodePrimitives for OpRbuilderPrimitives { + type Block = reth_primitives::Block; +} + +/// Type configuration for an Optimism rbuilder. #[derive(Debug, Default, Clone)] #[non_exhaustive] pub struct OpRbuilderNode { @@ -56,12 +65,15 @@ impl OpRbuilderNode { Node, OpRbuilderPoolBuilder, OpRbuilderPayloadServiceBuilder, - OptimismNetworkBuilder, - OptimismExecutorBuilder, - OptimismConsensusBuilder, + OpNetworkBuilder, + OpExecutorBuilder, + OpConsensusBuilder, > where - Node: FullNodeTypes, + Node: FullNodeTypes< + Types: NodeTypesWithEngine, + >, + <::Provider as DatabaseProviderFactory>::Provider: BlockReader, { let OpRbuilderArgs { disable_txpool_gossip, @@ -73,44 +85,52 @@ impl OpRbuilderNode { ComponentsBuilder::default() .node_types::() .pool(OpRbuilderPoolBuilder::new(rbuilder_config_path)) - .payload(OpRbuilderPayloadServiceBuilder::new( - compute_pending_block, - OptimismEvmConfig::default(), - )) - .network(OptimismNetworkBuilder { + .payload(OpRbuilderPayloadServiceBuilder::new(compute_pending_block)) + .network(OpNetworkBuilder { disable_txpool_gossip, disable_discovery_v4: !discovery_v4, }) - .executor(OptimismExecutorBuilder::default()) - .consensus(OptimismConsensusBuilder::default()) + .executor(OpExecutorBuilder::default()) + .consensus(OpConsensusBuilder::default()) } } impl Node for OpRbuilderNode where - N: FullNodeTypes, + N: FullNodeTypes>, + <::Provider as DatabaseProviderFactory>::Provider: BlockReader, { type ComponentsBuilder = ComponentsBuilder< N, OpRbuilderPoolBuilder, OpRbuilderPayloadServiceBuilder, - OptimismNetworkBuilder, - OptimismExecutorBuilder, - OptimismConsensusBuilder, + OpNetworkBuilder, + OpExecutorBuilder, + OpConsensusBuilder, >; - type AddOns = OptimismAddOns; + type AddOns = OptimismAddOns< + NodeAdapter>::Components>, + >; fn components_builder(&self) -> Self::ComponentsBuilder { let Self { args } = self; Self::components(args.clone()) } + + fn add_ons(&self) -> Self::AddOns { + OptimismAddOns::new(self.args.sequencer_http.clone()) + } } impl NodeTypes for OpRbuilderNode { - type Primitives = (); - type Engine = OptimismEngineTypes; - type ChainSpec = ChainSpec; + type Primitives = OpPrimitives; + type ChainSpec = OpChainSpec; + type StateCommitment = MerklePatriciaTrie; +} + +impl NodeTypesWithEngine for OpRbuilderNode { + type Engine = OpEngineTypes; } /// An extended optimism transaction pool with bundle support. @@ -138,7 +158,8 @@ pub type OpRbuilderTransactionPool = BundleSupportedPool< impl PoolBuilder for OpRbuilderPoolBuilder where - Node: FullNodeTypes, + Node: FullNodeTypes>, + <::Provider as DatabaseProviderFactory>::Provider: BlockReader, { type Pool = OpRbuilderTransactionPool; @@ -146,21 +167,23 @@ where let data_dir = ctx.config().datadir(); let blob_store = DiskFileBlobStore::open(data_dir.blobstore(), Default::default())?; - let validator = TransactionValidationTaskExecutor::eth_builder(ctx.chain_spec()) - .with_head_timestamp(ctx.head().timestamp) - .kzg_settings(ctx.kzg_settings()?) - .with_additional_tasks(ctx.config().txpool.additional_validation_tasks) - .build_with_tasks( - ctx.provider().clone(), - ctx.task_executor().clone(), - blob_store.clone(), - ) - .map(|validator| { - OpTransactionValidator::new(validator) - // In --dev mode we can't require gas fees because we're unable to decode the L1 - // block info - .require_l1_data_gas_fee(!ctx.config().dev.dev) - }); + let validator = TransactionValidationTaskExecutor::eth_builder(Arc::new( + ctx.chain_spec().inner.clone(), + )) + .with_head_timestamp(ctx.head().timestamp) + .kzg_settings(ctx.kzg_settings()?) + .with_additional_tasks(ctx.config().txpool.additional_validation_tasks) + .build_with_tasks( + ctx.provider().clone(), + ctx.task_executor().clone(), + blob_store.clone(), + ) + .map(|validator| { + OpTransactionValidator::new(validator) + // In --dev mode we can't require gas fees because we're unable to decode the L1 + // block info + .require_l1_data_gas_fee(!ctx.config().dev.dev) + }); let bundle_ops = BundlePoolOps::new(ctx.provider().clone(), self.rbuilder_config_path) .await @@ -214,9 +237,9 @@ where } } -/// A op-rbuilder payload service builder +/// An OP rbuilder payload service builder. #[derive(Debug, Default, Clone)] -pub struct OpRbuilderPayloadServiceBuilder { +pub struct OpRbuilderPayloadServiceBuilder { /// By default the pending block equals the latest block /// to save resources and not leak txs from the tx-pool, /// this flag enables computing of the pending block @@ -226,38 +249,38 @@ pub struct OpRbuilderPayloadServiceBuilder { /// will use the payload attributes from the latest block. Note /// that this flag is not yet functional. pub compute_pending_block: bool, - /// The EVM configuration to use for the payload builder. - pub evm_config: EVM, } -impl OpRbuilderPayloadServiceBuilder { - /// Create a new instance with the given `compute_pending_block` flag and evm config. - pub const fn new(compute_pending_block: bool, evm_config: EVM) -> Self { +impl OpRbuilderPayloadServiceBuilder { + /// Create a new instance with the given `compute_pending_block` flag. + pub const fn new(compute_pending_block: bool) -> Self { Self { compute_pending_block, - evm_config, } } -} -impl PayloadServiceBuilder for OpRbuilderPayloadServiceBuilder -where - Node: FullNodeTypes, - Pool: TransactionPoolBundleExt - + BundlePoolOperations - + Unpin - + 'static, - EVM: ConfigureEvm, -{ - async fn spawn_payload_service( + /// A helper method to initialize [`PayloadBuilderService`] with the given EVM config. + pub fn spawn( self, + evm_config: Evm, ctx: &BuilderContext, pool: Pool, - ) -> eyre::Result> { - let payload_builder = op_rbuilder_payload_builder::OpRbuilderPayloadBuilder::new( - OptimismEvmConfig::default(), - ) - .set_compute_pending_block(self.compute_pending_block); + ) -> eyre::Result> + where + Node: FullNodeTypes< + Types: NodeTypesWithEngine, + >, + <::Provider as DatabaseProviderFactory>::Provider: BlockReader, + Pool: TransactionPoolBundleExt + + BundlePoolOperations + + Unpin + + 'static, + + Evm: ConfigureEvm
, + { + let payload_builder = + op_rbuilder_payload_builder::OpRbuilderPayloadBuilder::new(evm_config) + .set_compute_pending_block(self.compute_pending_block); let conf = ctx.payload_builder_config(); let payload_job_config = BasicPayloadJobGeneratorConfig::default() @@ -272,7 +295,6 @@ where pool, ctx.task_executor().clone(), payload_job_config, - ctx.chain_spec(), payload_builder, ); let (payload_service, payload_builder) = @@ -284,3 +306,22 @@ where Ok(payload_builder) } } + +impl PayloadServiceBuilder for OpRbuilderPayloadServiceBuilder +where + Node: + FullNodeTypes>, + <::Provider as DatabaseProviderFactory>::Provider: BlockReader, + Pool: TransactionPoolBundleExt + + BundlePoolOperations + + Unpin + + 'static, +{ + async fn spawn_payload_service( + self, + ctx: &BuilderContext, + pool: Pool, + ) -> eyre::Result> { + self.spawn(OpEvmConfig::new(ctx.chain_spec()), ctx, pool) + } +} diff --git a/crates/op-rbuilder/payload_builder/Cargo.toml b/crates/op-rbuilder/payload_builder/Cargo.toml index ca4e1ca6..38885cf5 100644 --- a/crates/op-rbuilder/payload_builder/Cargo.toml +++ b/crates/op-rbuilder/payload_builder/Cargo.toml @@ -12,13 +12,16 @@ transaction-pool-bundle-ext = { path = "../../transaction-pool-bundle-ext" } reth-chainspec.workspace = true reth-primitives.workspace = true reth-revm.workspace = true -reth-rpc-types.workspace = true reth-provider.workspace = true reth-evm.workspace = true -reth-evm-optimism.workspace = true -reth-node-optimism.workspace = true +reth-optimism-evm.workspace = true +reth-optimism-consensus.workspace = true +reth-optimism-chainspec.workspace = true +reth-optimism-forks.workspace = true +reth-optimism-node.workspace = true reth-execution-types.workspace = true reth-payload-builder.workspace = true +reth-payload-primitives.workspace = true reth-basic-payload-builder.workspace = true reth-trie.workspace = true reth-chain-state.workspace = true @@ -26,19 +29,23 @@ reth-optimism-payload-builder.workspace = true # ethereum revm.workspace = true +alloy-consensus.workspace = true +op-alloy-consensus.workspace = true +alloy-eips.workspace = true +alloy-rpc-types-engine.workspace = true +alloy-rpc-types-beacon.workspace = true # misc tracing.workspace = true [features] optimism = [ - "reth-chainspec/optimism", - "reth-primitives/optimism", - "reth-provider/optimism", - "reth-node-optimism/optimism", - "reth-evm-optimism/optimism", - "reth-revm/optimism", "reth-execution-types/optimism", + "reth-optimism-evm/optimism", + "reth-optimism-node/optimism", "reth-optimism-payload-builder/optimism", - "revm/optimism" + "reth-primitives/optimism", + "reth-provider/optimism", + "revm/optimism", + "reth-optimism-consensus/optimism" ] diff --git a/crates/op-rbuilder/payload_builder/src/builder.rs b/crates/op-rbuilder/payload_builder/src/builder.rs index a00db5e6..84e75c26 100644 --- a/crates/op-rbuilder/payload_builder/src/builder.rs +++ b/crates/op-rbuilder/payload_builder/src/builder.rs @@ -1,28 +1,32 @@ //! Optimism payload builder implementation with Flashbots bundle support. +use alloy_consensus::{BlockHeader, Transaction, EMPTY_OMMER_ROOT_HASH}; +use alloy_eips::merge::BEACON_NONCE; +use alloy_rpc_types_beacon::events::{PayloadAttributesData, PayloadAttributesEvent}; +use alloy_rpc_types_engine::payload::PayloadAttributes; +use op_alloy_consensus::DepositTransaction; use reth_basic_payload_builder::*; use reth_chain_state::ExecutedBlock; -use reth_chainspec::{EthereumHardforks, OptimismHardfork}; -use reth_evm::{system_calls::pre_block_beacon_root_contract_call, ConfigureEvm}; +use reth_chainspec::ChainSpecProvider; +use reth_evm::{system_calls::SystemCaller, ConfigureEvm, ConfigureEvmEnv, NextBlockEnvAttributes}; use reth_execution_types::ExecutionOutcome; -use reth_node_optimism::{OptimismBuiltPayload, OptimismPayloadBuilderAttributes}; +use reth_optimism_chainspec::OpChainSpec; +use reth_optimism_consensus::calculate_receipt_root_no_memo_optimism; +use reth_optimism_forks::OptimismHardforks; +use reth_optimism_node::{OpBuiltPayload, OpPayloadBuilderAttributes}; use reth_optimism_payload_builder::error::OptimismPayloadBuilderError; -use reth_payload_builder::error::PayloadBuilderError; -use reth_primitives::{ - constants::{BEACON_NONCE, EMPTY_RECEIPTS, EMPTY_TRANSACTIONS}, - eip4844::calculate_excess_blob_gas, - proofs, Block, Header, Receipt, TransactionSigned, TxType, EMPTY_OMMER_ROOT_HASH, U256, -}; +use reth_payload_builder::PayloadBuilderError; +use reth_payload_primitives::PayloadBuilderAttributes; +use reth_primitives::{proofs, Block, BlockBody, Header, Receipt, TransactionSigned, TxType}; use reth_provider::StateProviderFactory; use reth_revm::database::StateProviderDatabase; -use reth_rpc_types::{ - beacon::events::{PayloadAttributesData, PayloadAttributesEvent}, - engine::PayloadAttributes, -}; use reth_trie::HashedPostState; use revm::{ db::states::bundle_state::BundleRetention, - primitives::{EVMError, EnvWithHandlerCfg, InvalidTransaction, ResultAndState}, + primitives::{ + BlockEnv, CfgEnvWithHandlerCfg, EVMError, EnvWithHandlerCfg, InvalidTransaction, + ResultAndState, U256, + }, DatabaseCommit, State, }; use std::sync::Arc; @@ -63,22 +67,44 @@ impl OpRbuilderPayloadBuilder { } } +impl OpRbuilderPayloadBuilder +where + EvmConfig: ConfigureEvmEnv
, +{ + /// Returns the configured [`CfgEnvWithHandlerCfg`] and [`BlockEnv`] for the targeted payload + /// (that has the `parent` as its parent). + pub fn cfg_and_block_env( + &self, + config: &PayloadConfig, + parent: &Header, + ) -> Result<(CfgEnvWithHandlerCfg, BlockEnv), EvmConfig::Error> { + let next_attributes = NextBlockEnvAttributes { + timestamp: config.attributes.timestamp(), + suggested_fee_recipient: config.attributes.suggested_fee_recipient(), + prev_randao: config.attributes.prev_randao(), + }; + self.evm_config + .next_cfg_and_block_env(parent, next_attributes) + } +} + /// Implementation of the [`PayloadBuilder`] trait for [`OpRbuilderPayloadBuilder`]. impl PayloadBuilder for OpRbuilderPayloadBuilder where - Client: StateProviderFactory, - EvmConfig: ConfigureEvm, + Client: StateProviderFactory + ChainSpecProvider, + EvmConfig: ConfigureEvm
, Pool: TransactionPoolBundleExt + BundlePoolOperations, { - type Attributes = OptimismPayloadBuilderAttributes; - type BuiltPayload = OptimismBuiltPayload; + type Attributes = OpPayloadBuilderAttributes; + type BuiltPayload = OpBuiltPayload; fn try_build( &self, - args: BuildArguments, - ) -> Result, PayloadBuilderError> { - let parent_block = args.config.parent_block.clone(); - // Notify our BundleOperations of the new bundle. + args: BuildArguments, + ) -> Result, PayloadBuilderError> { + let parent_header = args.config.parent_header.clone(); + + // Notify our BundleOperations of the new payload attributes event. let eth_payload_attributes = args.config.attributes.payload_attributes.clone(); let payload_attributes = PayloadAttributes { timestamp: eth_payload_attributes.timestamp, @@ -88,10 +114,10 @@ where suggested_fee_recipient: eth_payload_attributes.suggested_fee_recipient, }; let payload_attributes_data = PayloadAttributesData { - parent_block_number: parent_block.number, - parent_block_root: parent_block.header.hash(), - parent_block_hash: parent_block.hash(), - proposal_slot: parent_block.number + 1, + parent_block_number: parent_header.number, + parent_block_root: parent_header.state_root(), + parent_block_hash: parent_header.hash(), + proposal_slot: parent_header.number + 1, proposer_index: 0, // Shouldn't be required for core building logic payload_attributes, }; @@ -106,143 +132,36 @@ where ) { error!(?e, "Failed to notify payload attributes event!"); }; - try_build_inner(self.evm_config.clone(), args, self.compute_pending_block) + + let (cfg_env, block_env) = self + .cfg_and_block_env(&args.config, &args.config.parent_header) + .map_err(PayloadBuilderError::other)?; + try_build_inner( + &self.evm_config, + args, + cfg_env, + block_env, + self.compute_pending_block, + ) } fn on_missing_payload( &self, - _args: BuildArguments, + _args: BuildArguments, ) -> MissingPayloadBehaviour { // we want to await the job that's already in progress because that should be returned as // is, there's no benefit in racing another job MissingPayloadBehaviour::AwaitInProgress } + // NOTE: this should only be used for testing purposes because this doesn't have access to L1 + // system txs, hence on_missing_payload we return [MissingPayloadBehaviour::AwaitInProgress]. fn build_empty_payload( &self, - client: &Client, - config: PayloadConfig, - ) -> Result { - let extra_data = config.extra_data(); - let PayloadConfig { - initialized_block_env, - parent_block, - attributes, - chain_spec, - .. - } = config; - - debug!(target: "payload_builder", parent_hash = ?parent_block.hash(), parent_number = parent_block.number, "building empty payload"); - - let state = client.state_by_block_hash(parent_block.hash()).map_err(|err| { - warn!(target: "payload_builder", parent_hash=%parent_block.hash(), %err, "failed to get state for empty payload"); - err - })?; - let mut db = State::builder() - .with_database(StateProviderDatabase::new(state)) - .with_bundle_update() - .build(); - - let base_fee = initialized_block_env.basefee.to::(); - let block_gas_limit: u64 = initialized_block_env - .gas_limit - .try_into() - .unwrap_or(chain_spec.max_gas_limit); - - let WithdrawalsOutcome { - withdrawals_root, - withdrawals, - } = commit_withdrawals( - &mut db, - &chain_spec, - attributes.payload_attributes.timestamp, - attributes.payload_attributes.withdrawals.clone(), - ) - .map_err(|err| { - warn!(target: "payload_builder", - parent_hash=%parent_block.hash(), - %err, - "failed to commit withdrawals for empty payload" - ); - err - })?; - - // merge all transitions into bundle state, this would apply the withdrawal balance - // changes and 4788 contract call - db.merge_transitions(BundleRetention::PlainState); - - // calculate the state root - let bundle_state = db.take_bundle(); - let hashed_state = HashedPostState::from_bundle_state(&bundle_state.state); - let state_root = db.database.state_root(hashed_state).map_err(|err| { - warn!(target: "payload_builder", - parent_hash=%parent_block.hash(), - %err, - "failed to calculate state root for empty payload" - ); - err - })?; - - let mut excess_blob_gas = None; - let mut blob_gas_used = None; - - if chain_spec.is_cancun_active_at_timestamp(attributes.payload_attributes.timestamp) { - excess_blob_gas = if chain_spec.is_cancun_active_at_timestamp(parent_block.timestamp) { - let parent_excess_blob_gas = parent_block.excess_blob_gas.unwrap_or_default(); - let parent_blob_gas_used = parent_block.blob_gas_used.unwrap_or_default(); - Some(calculate_excess_blob_gas( - parent_excess_blob_gas, - parent_blob_gas_used, - )) - } else { - // for the first post-fork block, both parent.blob_gas_used and - // parent.excess_blob_gas are evaluated as 0 - Some(calculate_excess_blob_gas(0, 0)) - }; - - blob_gas_used = Some(0); - } - let header = Header { - parent_hash: parent_block.hash(), - ommers_hash: EMPTY_OMMER_ROOT_HASH, - beneficiary: initialized_block_env.coinbase, - state_root, - transactions_root: EMPTY_TRANSACTIONS, - withdrawals_root, - receipts_root: EMPTY_RECEIPTS, - logs_bloom: Default::default(), - timestamp: attributes.payload_attributes.timestamp, - mix_hash: attributes.payload_attributes.prev_randao, - nonce: BEACON_NONCE, - base_fee_per_gas: Some(base_fee), - number: parent_block.number + 1, - gas_limit: block_gas_limit, - difficulty: U256::ZERO, - gas_used: 0, - extra_data, - blob_gas_used, - excess_blob_gas, - parent_beacon_block_root: attributes.payload_attributes.parent_beacon_block_root, - requests_root: None, - }; - - let block = Block { - header, - body: vec![], - ommers: vec![], - withdrawals, - requests: None, - }; - let sealed_block = block.seal_slow(); - - Ok(OptimismBuiltPayload::new( - attributes.payload_attributes.payload_id(), - sealed_block, - U256::ZERO, - chain_spec, - attributes, - None, - )) + _client: &Client, + _config: PayloadConfig, + ) -> Result { + Err(PayloadBuilderError::MissingPayload) } } @@ -254,13 +173,15 @@ where /// a result indicating success with the payload or an error in case of failure. #[inline] pub(crate) fn try_build_inner( - evm_config: EvmConfig, - args: BuildArguments, + evm_config: &EvmConfig, + args: BuildArguments, + initialized_cfg: CfgEnvWithHandlerCfg, + initialized_block_env: BlockEnv, _compute_pending_block: bool, -) -> Result, PayloadBuilderError> +) -> Result, PayloadBuilderError> where - EvmConfig: ConfigureEvm, - Client: StateProviderFactory, + Client: StateProviderFactory + ChainSpecProvider, + EvmConfig: ConfigureEvm
, Pool: TransactionPoolBundleExt + BundlePoolOperations, { let BuildArguments { @@ -272,23 +193,20 @@ where best_payload, } = args; - let state_provider = client.state_by_block_hash(config.parent_block.hash())?; + let chain_spec = client.chain_spec(); + let state_provider = client.state_by_block_hash(config.parent_header.hash())?; let state = StateProviderDatabase::new(state_provider); let mut db = State::builder() - .with_database_ref(cached_reads.as_db(state)) + .with_database(cached_reads.as_db_mut(state)) .with_bundle_update() .build(); - let extra_data = config.extra_data(); let PayloadConfig { - initialized_block_env, - initialized_cfg, - parent_block, + parent_header, attributes, - chain_spec, - .. + mut extra_data, } = config; - debug!(target: "payload_builder", id=%attributes.payload_attributes.payload_id(), parent_hash = ?parent_block.hash(), parent_number = parent_block.number, "building new payload"); + debug!(target: "payload_builder", id=%attributes.payload_attributes.payload_id(), parent_header = ?parent_header.hash(), parent_number = parent_header.number, "building new payload"); let mut cumulative_gas_used = 0; let block_gas_limit: u64 = attributes.gas_limit.unwrap_or_else(|| { @@ -306,34 +224,33 @@ where let block_number = initialized_block_env.number.to::(); - let is_regolith = chain_spec.is_fork_active_at_timestamp( - OptimismHardfork::Regolith, - attributes.payload_attributes.timestamp, - ); + let is_regolith = + chain_spec.is_regolith_active_at_timestamp(attributes.payload_attributes.timestamp); // apply eip-4788 pre block contract call - pre_block_beacon_root_contract_call( - &mut db, - &evm_config, - &chain_spec, - &initialized_cfg, - &initialized_block_env, - attributes.payload_attributes.parent_beacon_block_root, - ) - .map_err(|err| { - warn!(target: "payload_builder", - parent_hash=%parent_block.hash(), - %err, - "failed to apply beacon root contract call for empty payload" - ); - PayloadBuilderError::Internal(err.into()) - })?; + let mut system_caller = SystemCaller::new(evm_config.clone(), chain_spec.clone()); + + system_caller + .pre_block_beacon_root_contract_call( + &mut db, + &initialized_cfg, + &initialized_block_env, + attributes.payload_attributes.parent_beacon_block_root, + ) + .map_err(|err| { + warn!(target: "payload_builder", + parent_header=%parent_header.hash(), + %err, + "failed to apply beacon root contract call for payload" + ); + PayloadBuilderError::Internal(err.into()) + })?; // Ensure that the create2deployer is force-deployed at the canyon transition. Optimism // blocks will always have at least a single transaction in them (the L1 info transaction), // so we can safely assume that this will always be triggered upon the transition and that // the above check for empty blocks will never be hit on OP chains. - reth_evm_optimism::ensure_create2_deployer( + reth_optimism_evm::ensure_create2_deployer( chain_spec.clone(), attributes.payload_attributes.timestamp, &mut db, @@ -389,7 +306,7 @@ where let env = EnvWithHandlerCfg::new_with_cfg_env( initialized_cfg.clone(), initialized_block_env.clone(), - evm_config.tx_env(&sequencer_tx), + evm_config.tx_env(sequencer_tx.as_signed(), sequencer_tx.signer()), ); let mut evm = evm_config.evm_with_env(&mut db, env); @@ -431,10 +348,7 @@ where // receipt hashes should be computed when set. The state transition process // ensures this is only set for post-Canyon deposit transactions. deposit_receipt_version: chain_spec - .is_fork_active_at_timestamp( - OptimismHardfork::Canyon, - attributes.payload_attributes.timestamp, - ) + .is_canyon_active_at_timestamp(attributes.payload_attributes.timestamp) .then_some(1), })); @@ -446,7 +360,7 @@ where // Apply rbuilder block let mut count = 0; let iter = pool - .get_transactions(U256::from(parent_block.number + 1)) + .get_transactions(U256::from(parent_header.number + 1)) .unwrap() .into_iter(); for pool_tx in iter { @@ -478,7 +392,7 @@ where let env = EnvWithHandlerCfg::new_with_cfg_env( initialized_cfg.clone(), initialized_block_env.clone(), - evm_config.tx_env(&tx), + evm_config.tx_env(tx.as_signed(), tx.signer()), ); // Configure the environment for the block. @@ -532,7 +446,7 @@ where // update add to total fees let miner_fee = tx - .effective_tip_per_gas(Some(base_fee)) + .effective_tip_per_gas(base_fee) .expect("fee is always valid; execution succeeded"); total_fees += U256::from(miner_fee) * U256::from(gas_used); @@ -544,7 +458,7 @@ where trace!("Executed {} txns from rbuilder", count); - // check if we have a better block + // check if we have a better block, but only if we included transactions from the pool if !is_better_payload(best_payload.as_ref(), total_fees) { // can skip building the block return Ok(BuildOutcome::Aborted { @@ -560,25 +474,23 @@ where &mut db, &chain_spec, attributes.payload_attributes.timestamp, - attributes.clone().payload_attributes.withdrawals, + attributes.payload_attributes.withdrawals.clone(), )?; // merge all transitions into bundle state, this would apply the withdrawal balance changes // and 4788 contract call - db.merge_transitions(BundleRetention::PlainState); + db.merge_transitions(BundleRetention::Reverts); let execution_outcome = ExecutionOutcome::new( db.take_bundle(), - vec![receipts].into(), + vec![receipts.clone()].into(), block_number, Vec::new(), ); let receipts_root = execution_outcome - .optimism_receipts_root_slow( - block_number, - chain_spec.as_ref(), - attributes.payload_attributes.timestamp, - ) + .generic_receipts_root_slow(block_number, |receipts| { + calculate_receipt_root_no_memo_optimism(receipts, &chain_spec, attributes.timestamp()) + }) .expect("Number is in range"); let logs_bloom = execution_outcome .block_logs_bloom(block_number) @@ -587,15 +499,14 @@ where // calculate the state root let hashed_state = HashedPostState::from_bundle_state(&execution_outcome.state().state); let (state_root, trie_output) = { - let state_provider = db.database.0.inner.borrow_mut(); - state_provider - .db + db.database + .inner() .state_root_with_updates(hashed_state.clone()) .inspect_err(|err| { warn!(target: "payload_builder", - parent_hash=%parent_block.hash(), + parent_header=%parent_header.hash(), %err, - "failed to calculate state root for empty payload" + "failed to calculate state root for payload" ); })? }; @@ -603,31 +514,29 @@ where // create the block header let transactions_root = proofs::calculate_transaction_root(&executed_txs); - // initialize empty blob sidecars. There are no blob transactions on L2. - let blob_sidecars = Vec::new(); - let mut excess_blob_gas = None; - let mut blob_gas_used = None; - - // only determine cancun fields when active - if chain_spec.is_cancun_active_at_timestamp(attributes.payload_attributes.timestamp) { - excess_blob_gas = if chain_spec.is_cancun_active_at_timestamp(parent_block.timestamp) { - let parent_excess_blob_gas = parent_block.excess_blob_gas.unwrap_or_default(); - let parent_blob_gas_used = parent_block.blob_gas_used.unwrap_or_default(); - Some(calculate_excess_blob_gas( - parent_excess_blob_gas, - parent_blob_gas_used, - )) + // OP doesn't support blobs/EIP-4844. + // https://specs.optimism.io/protocol/exec-engine.html#ecotone-disable-blob-transactions + // Need [Some] or [None] based on hardfork to match block hash. + let (excess_blob_gas, blob_gas_used) = + if chain_spec.is_ecotone_active_at_timestamp(attributes.payload_attributes.timestamp) { + (Some(0), Some(0)) } else { - // for the first post-fork block, both parent.blob_gas_used and - // parent.excess_blob_gas are evaluated as 0 - Some(calculate_excess_blob_gas(0, 0)) + (None, None) }; - blob_gas_used = Some(0); + let is_holocene = + chain_spec.is_holocene_active_at_timestamp(attributes.payload_attributes.timestamp); + + if is_holocene { + extra_data = attributes + .get_holocene_extra_data( + chain_spec.base_fee_params_at_timestamp(attributes.payload_attributes.timestamp), + ) + .map_err(PayloadBuilderError::other)?; } let header = Header { - parent_hash: parent_block.hash(), + parent_hash: parent_header.hash(), ommers_hash: EMPTY_OMMER_ROOT_HASH, beneficiary: initialized_block_env.coinbase, state_root, @@ -637,9 +546,9 @@ where logs_bloom, timestamp: attributes.payload_attributes.timestamp, mix_hash: attributes.payload_attributes.prev_randao, - nonce: BEACON_NONCE, + nonce: BEACON_NONCE.into(), base_fee_per_gas: Some(base_fee), - number: parent_block.number + 1, + number: parent_header.number + 1, gas_limit: block_gas_limit, difficulty: U256::ZERO, gas_used: cumulative_gas_used, @@ -647,16 +556,17 @@ where parent_beacon_block_root: attributes.payload_attributes.parent_beacon_block_root, blob_gas_used, excess_blob_gas, - requests_root: None, + requests_hash: None, }; // seal the block let block = Block { header, - body: executed_txs, - ommers: vec![], - withdrawals, - requests: None, + body: BlockBody { + transactions: executed_txs, + ommers: vec![], + withdrawals, + }, }; let sealed_block = block.seal_slow(); @@ -671,7 +581,7 @@ where trie: Arc::new(trie_output), }; - let mut payload = OptimismBuiltPayload::new( + let payload = OpBuiltPayload::new( attributes.payload_attributes.id, sealed_block, total_fees, @@ -680,9 +590,6 @@ where Some(executed), ); - // extend the payload with the blob sidecars from the executed txs - payload.extend_sidecars(blob_sidecars); - Ok(BuildOutcome::Better { payload, cached_reads, diff --git a/crates/op-rbuilder/src/main.rs b/crates/op-rbuilder/src/main.rs index 3350d78e..b899725d 100644 --- a/crates/op-rbuilder/src/main.rs +++ b/crates/op-rbuilder/src/main.rs @@ -36,9 +36,12 @@ use crate::eth_bundle_api::EthCallBundleMinimalApiServer; use clap_builder::Parser; use eth_bundle_api::EthBundleMinimalApi; use op_rbuilder_node_optimism::{args::OpRbuilderArgs, OpRbuilderNode}; -use reth::cli::Cli; -use reth_node_optimism::node::OptimismAddOns; -use reth_optimism_rpc::eth::rpc::SequencerClient; +use reth::{ + builder::{engine_tree_config::TreeConfig, EngineNodeLauncher}, + providers::providers::BlockchainProvider2, +}; +use reth_optimism_cli::{chainspec::OpChainSpecParser, Cli}; +use reth_optimism_node::node::OptimismAddOns; use tracing as _; // jemalloc provides better performance @@ -53,32 +56,58 @@ fn main() { std::env::set_var("RUST_BACKTRACE", "1"); } - if let Err(err) = Cli::::parse().run(|builder, op_rbuilder_args| async move { - let sequencer_http_arg = op_rbuilder_args.sequencer_http.clone(); - let handle = builder - .with_types::() - .with_components(OpRbuilderNode::components(op_rbuilder_args)) - .with_add_ons::() - .extend_rpc_modules(move |ctx| { - // register sequencer tx forwarder - if let Some(sequencer_http) = sequencer_http_arg { - ctx.registry - .eth_api() - .set_sequencer_client(SequencerClient::new(sequencer_http)); - } + if let Err(err) = + Cli::::parse().run(|builder, op_rbuilder_args| async move { + if op_rbuilder_args.experimental { + tracing::warn!(target: "reth::cli", "Experimental engine is default now, and the --engine.experimental flag is deprecated. To enable the legacy functionality, use --engine.legacy."); + } + let use_legacy_engine = op_rbuilder_args.legacy; + let sequencer_http_arg = op_rbuilder_args.sequencer_http.clone(); + match use_legacy_engine { + false => { + let engine_tree_config = TreeConfig::default() + .with_persistence_threshold(op_rbuilder_args.persistence_threshold) + .with_memory_block_buffer_target(op_rbuilder_args.memory_block_buffer_target); + let handle = builder + .with_types_and_provider::>() + .with_components(OpRbuilderNode::components(op_rbuilder_args)) + .with_add_ons(OptimismAddOns::new(sequencer_http_arg)) + .extend_rpc_modules(move |ctx| { + // register eth bundle api + let ext = EthBundleMinimalApi::new(ctx.registry.pool().clone()); + ctx.modules.merge_configured(ext.into_rpc())?; - // register eth bundle api - let ext = EthBundleMinimalApi::new(ctx.registry.pool().clone()); - ctx.modules.merge_configured(ext.into_rpc())?; + Ok(()) + }) + .launch_with_fn(|builder| { + let launcher = EngineNodeLauncher::new( + builder.task_executor().clone(), + builder.config().datadir(), + engine_tree_config, + ); + builder.launch_with(launcher) + }) + .await?; - Ok(()) - }) - .launch() - .await?; + handle.node_exit_future.await + } + true => { + let handle = + builder + .node(OpRbuilderNode::new(op_rbuilder_args.clone())).extend_rpc_modules(move |ctx| { + // register eth bundle api + let ext = EthBundleMinimalApi::new(ctx.registry.pool().clone()); + ctx.modules.merge_configured(ext.into_rpc())?; - handle.node_exit_future.await - }) { - eprintln!("Error: {err:?}"); - std::process::exit(1); - } + Ok(()) + }) + .launch().await?; + handle.node_exit_future.await + } + } + }) + { + eprintln!("Error: {err:?}"); + std::process::exit(1); + } } diff --git a/crates/rbuilder/Cargo.toml b/crates/rbuilder/Cargo.toml index de118f14..9b7f6a5c 100644 --- a/crates/rbuilder/Cargo.toml +++ b/crates/rbuilder/Cargo.toml @@ -33,6 +33,7 @@ reth-evm-ethereum.workspace = true revm.workspace = true revm-primitives.workspace = true revm-inspectors.workspace = true +reth-node-ethereum.workspace = true alloy-primitives.workspace = true alloy-rlp.workspace = true @@ -123,7 +124,7 @@ derivative = "2.2.0" mockall = "0.12.1" shellexpand = "3.1.0" async-trait = "0.1.80" - +foldhash = "0.1.3" eth-sparse-mpt.workspace = true crossbeam = "0.8.4" parking_lot = "0.12.3" @@ -138,12 +139,10 @@ criterion = { version = "0.5.1", features = ["html_reports", "async_tokio"] } [features] optimism = [ - "reth-chainspec/optimism", - "reth-provider/optimism", - "reth/optimism", "reth-db/optimism", "reth-node-core/optimism", "reth-primitives/optimism", + "reth-provider/optimism", "revm-primitives/optimism", "revm/optimism" ] diff --git a/crates/rbuilder/benches/benchmarks/mev_boost.rs b/crates/rbuilder/benches/benchmarks/mev_boost.rs index 1747dbcb..bf6614b5 100644 --- a/crates/rbuilder/benches/benchmarks/mev_boost.rs +++ b/crates/rbuilder/benches/benchmarks/mev_boost.rs @@ -1,5 +1,4 @@ -use alloy_primitives::{hex, BlockHash, U256}; -use alloy_rlp::Decodable; +use alloy_primitives::{BlockHash, U256}; use criterion::{criterion_group, Criterion}; use primitive_types::H384; use rbuilder::mev_boost::{ @@ -7,7 +6,7 @@ use rbuilder::mev_boost::{ }; use reth::primitives::{BlobTransactionSidecar, SealedBlock}; use reth_chainspec::SEPOLIA; -use reth_primitives::SealedHeader; +use reth_primitives::{kzg::Blob, SealedHeader}; use std::{fs, path::PathBuf, sync::Arc}; fn mev_boost_serialize_submit_block(data: DenebSubmitBlockRequest) { @@ -44,13 +43,27 @@ fn bench_mevboost_serialization(c: &mut Criterion) { fn bench_mevboost_sign(c: &mut Criterion) { let mut generator = TestDataGenerator::default(); - let blob_rlp = fs::read_to_string( - PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("benches/blob_data/blob1.txt"), + let json_content = fs::read_to_string( + PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("benches/blob_data/blob1.json"), ) .unwrap(); - let blob_rlp = hex::decode(blob_rlp).unwrap(); - let blob = BlobTransactionSidecar::decode(&mut blob_rlp.as_slice()).unwrap(); + // Parse the JSON contents into a serde_json::Value + let json_value: serde_json::Value = + serde_json::from_str(&json_content).expect("Failed to deserialize JSON"); + + // Extract blob data from JSON and convert it to Blob + let blobs: Vec = vec![Blob::from_hex( + json_value + .get("data") + .unwrap() + .as_str() + .expect("Data is not a valid string"), + ) + .unwrap()]; + + // Generate a BlobTransactionSidecar from the blobs + let blob = BlobTransactionSidecar::try_from_blobs(blobs).unwrap(); let sealed_block = SealedBlock::default(); let signer = BLSBlockSigner::test_signer(); @@ -71,6 +84,7 @@ fn bench_mevboost_sign(c: &mut Criterion) { &signer, &sealed_block, &blobs, + &Vec::new(), &chain_spec, &payload, H384::default(), @@ -95,6 +109,7 @@ fn bench_mevboost_sign(c: &mut Criterion) { &signer, &sealed_block_deneb, &blobs, + &Vec::new(), &chain_spec, &payload, H384::default(), diff --git a/crates/rbuilder/benches/blob_data/blob1.json b/crates/rbuilder/benches/blob_data/blob1.json new file mode 100644 index 00000000..f659249b --- /dev/null +++ b/crates/rbuilder/benches/blob_data/blob1.json @@ -0,0 +1 @@ +{"commitment":"8d0960141c238395fc463bf31ccfa1d0a21216cb4fa534a780b6acc6b56d2345d220937631e790b2600d4c9b117a5ff4","data":"001611aa000000034277ff00ff0001feed56d1420ee27fe2a5e11539680a339a004bb25733b142e13399f2561ee370566c9a7b1533fbb1fd7bf9c45bde68111d004af20972a34d3988eed31121ad9020360a3a5734e146fae3a729592b0badad0051d44b83a40120dd47368416383c686d86796abcb6b031d4f8871ba79164a100c3824e1dce8ba21fe35754a7d0d2c6d8c4c37d526b67ba3057d91a88a7f46f00b27bb885c310ac601f5634f6e9d6f7c5730efbfb2284ad319997e2eb68d65900053e85b0c6ec5c683da7e728615e42578ba96e21f855c1a337537001fd5bc40063bf707e416db4ebdb38c8a48ef86bc47126524c4c1563e03b411a66daeae2003a41cc79ed8e94029745ef64667b2568cddc250aa5105558b276aa3a245a3300dbc71649b84cab6ee79ac1ffae3a4bb0d81a269894310fe1d1e071bdfb89ba00ce1c2821ef0e30551ecd4ab51cf09abeeea314b761f01f891bdf5e3855779e00815e4b708291a6e1d9cc35dc1ef4629a206adec20e717a4a42f5a2354ca4e3008de7ef2ab714c988f8362d082b9bb555c74b30ab8d9cdd3ad89921ca3d3d6c002729f7108589d22820f3a04f0ae347338cc94bf17a0d838fd44eb3c36661d5008a0b5603b5253c210e6fa3c614047e119368c08e405a4343cad97d6b30ecce000a22a3019046205c6aadfeb6459fd091eaee31af225ff8fee6f5543eb37315003b7cab9472a501121a62ca3e870e231649e6e833b58e76f3b5a61f33b367b700dacf4d1d05d68191dff0c47edf65198c20b04834e0b854302b280d0ecce19c00b253300b966636b121034474f4344834723d2b901dff586e74e73fccc5b08300968dbd39417caec3ec90243aa7cd7ef54e00a4cc6362ae7309c8fd19be1fd7009b12420b6a7d2047bd9f7c0e6fe7c29d898d2187d0c0afa970e9506e40d3cb00427f470c7367c4fe07f2dc0afdd7f0646f7968c462417bf8e39be303f235b8004d5f1f1e51c2b027b2f0910a91fb5b50131c423659fec5e833b29a440996bf009c7c8dfeba6eab6132b8b7bcc55f29ef71385d646d5f7a9b058808c1347b63009e8b03adc33e553d98de1e1e9017c3976ac910a662f277e908084c9be6f737007846e4e4067098bec934c724e060c853b36ee1ff2dafb1156a0ccec963895e00188ffee8def41363e0cb485934df99abbc4bcab9800c0a922f4a9f74048aaa00b2a2b5eb5361f4ef50a13f084f336375ee192632e04a7f1781880f71f8865b00db7dfd640158126e7ef64cd14f1bfd12a86eff35ddad3ee6333bd63d9b8e1400065e6d2e82e6b9e9ac59a118c02aa6d67670c0f7e81228300008cf011df911006a0a6e5b4156ba479edd7f4b1c84c734dba7e157ad2162003ae3900913c14d0067db3dbdffa02113812eb1a335c7b6c2eed10c0b5f5799ee6a83fd0b9ee38b0057cbc9951de3f173841428e42e5a45bdd9caac835e32562c844c0198b1370800da9286a62bc6d4fdc3770c33fec9bd93417e8749ce365c93c0a0492de46f12001d14724b9b599a3cc379522667cb7167a9bf597f5822cc48a4819b126d2af2001d60ee6bfa37daa3e7d44c6cd19d423f8f3d7736894fd0e7e5f43386bcfc3d00fc465e9494d92c70a5f84132dc2677303794e32964aa816282c01b896c509000e7d4f24ae15ff8cbabb34e2b2c2e728f904ab2f65ccba24abdd466962b4ce700b9b71fec11ef172ef874bcb13a342141ffa3a6ef8fa85eb621e84f9bfa60680024b1d0d4dcb9ff2164456c91dbfe309d49405dac779ed817c6ed3fec1f6b250081caf3c47793d742560e99cd8fc7ded219f13b150b052d575b86015621a1fd00d128654c6f496dd0d845e85129d1e628703eb688fc701f2edbe890e6cf8f5f00729968509f66b656abfa3edbe0610dbd700fe90e8a2bdf1aab61c5f94f3b6800bc898d258be0ce512c97ccd819f834bc74ee94f09d7f0287515c24fe2d0631001205ab32ec99f3eb997af0f33de1a150d4ea23a12c00f73c8f8b9844e9005d007cc3a76310eec403fb4d078d03e8f299ede73538e7c4f28a6390daef7009c80036e51be5dd4894a96c4c54029c64b4ee0a71b3e26bf2a309b1a4a2e0b259d000b1d8f11a3261287d2784527867e47fe54cc4a1864110b42d2848c859068d870008d721726aae0b412ec7a93580a262de23c17a00dd23f892adf4b886671ed400c268328407a5ce9b6922ec840e6356827781b80b2eb07da3115f72187f0b90004ee876c6daf22b1d9b05b3b0379caf04616a05b5c33ce6143d60741214f837002227369f6842e45357580171b5233f55f5192acc1ed613ab9353579576ba12004ea22883f84a4d9096878942cd429061b465384b3db6b5a8d2a389a2ec956c0078ac6f47c24a06028cb1e3a6fca3582319b39852551627ab05beef36fa408700aa459f8f764c7b4c4a8e95784441b0a5ec12ec71be9e09cbd207bfe4191694005062474217acf247bc3a7b5668f7cd28ed2955a648b4c48672cf91e2c719e3006d35d7226f9773f80598414eb5447ef59c2c7a282af1a9410e6cd023dfedee00422cfb6dd05e38538766a084103f228b9ed6c685fdb983a7ed040dccb02208005816e95e3e90c627c72df1724d603df80a090dd856f7efcb188e931d0e40af00e7376b6bc7eae7c5118662abad7a45e1094566b404551511e2d27da77d6e0b006f1b6a64f2c7d2b24822c5def2d1857ec7bb8832c04e3e6c4bfd071edf38f400e209abfab858d9894f84cd2810d44e537a0a266f1c155e322f997c6dd41f8e000d4e7f79cac70e4eb1e2f86ddd5245f80b797a557e8f4ceea9c5fab7b96891004e42762fb70f8993aa543bdf5c484d5efeb714d0c8cae05fa7b6f13785343f00165e6e023f81e829a8e11ac34cbe4f110c0805e053dfc23afb9bfc7d55b8dc003b61641a11e494ad1f5200ca65bea50ced23682ad6cd7de71be4edc6161d6f00a07d9820d765e8db86a44a861243f03e9c9f6ae651d8e96b06c0073fc6a08d008fb35490de6f5cd2112fbb091ab8299c8e273e69af218af257a70ac4235fc800a9895dc058f34caf30e3db8d7db76486c54187732ba384197c5ba292c8e40d00ee2d0cadec12e228f732aa55bce56917fe5e681fd703733a6acdfc252383bd00df484d1c9c57701588be949013357587b976b0fcc1bd0c195fb50e6fb0661200a9a5f6f57f89775f314cfd41a953577b164689117a0e37c1274ac6c90a080f00758527bdf8c4414530c56116a4364c3bd212485132ad8ba49b104ce9ad45eb008dadf9bdff3367ba111b62af7968a2adb1bcf410f1d2ced305206b3d6fb02e00d137b2457d858f67454c68502903666a2e295a1dc901b77d7c67a4ea525963008d5d377c85f321224c13b8c9e7dbebb4f7bb0a5a54a49eec1c7c42106c034400ff03f702b37e5b5c8a8e8ff27c9ec3765ef48054e33ddfdf35a78d3568ab9b00a8fde32007eff93bcf3c8d0ab8c748d4ee8105c2d5dd396ea8d80cc78fb795002a4939ee2e8f957be8ee06fb0a741b01605483b142c2d1dfe770c2d84a7d9000935c2eb1f4ada8c9f7e95daca0147b4bd896ceaec0005c41c7cc1c82201655009ed0c70c957b359f41c1ec026cc4ec0f3471fbe8f8e969f232fd42e8637ddf0060db89d4cb0546c764cc01f72b30f3b18e13808fae67ab0e888f399c3faebb000817c11e77db5fa3c2e250723752f72614513fceb599bf04496a87b995209d00a0c8d6df62b44d025bb8d9ec848ceced74768d7cb4750299d9a53076e8833200c29f41aad9eb41dbcf7b560810e63d67d9566e161eb30beabd1ea08ad54df900aea612999cee8f3b0b44c930dc75f4f7bfd7e806abe033342434e672682fdd0022075f81636e85adf8bd89708e56db71ea1d8c400260d11f21e9dc3eab376600ca47660f07a25f86d357fe1297aba050f327087d4430bd56bf5152155efa1800ea3bab34998bd5e9805e6c32ad685a9d7363f734fdb9c995577104153b221700211a25bc376ccc14b67ab369b34d19008e7b1d6e85a76b6a1669572273202d00e359dcedd00be5908ae9cc323b504480ec67c6b28d9d4a13a41327a9050eb700293a0e5b5ae26d993b65405970b2aede2d57cc7545687e951e89a1c8372a7f000f2639dc196095c8d5a8793444e201787f8253c00044e324347e2351fb55c200d48d09d41572c319e8eff5ec7708e8073d742897443b37a8bdcc45a721050a00f290c50e6c44cc5be89eee2ba43dd458d5923b132d42149a14fe42fbfc5775005259df4a551fa5eb1893f869203caf11917e2c4c71e7c7bde475f13e99a7450002622eda5c8463d7329fba14036750fbad21241fb9d96878ea1f2412bb2bc500d5266dd616edb4af5e22705381f69c40a380402c16c123979dfd703d8fb88800c2b6e1e193dfc5832c2efd27a13df0eb984139c3488c1fa589e43283999dd300c1248ea7980ea9e1b6e8a325a8bc7f024dd9e406622527606bbeecb58dffa10079e2f26090e63158bd320d87e523fe61e7f3ab7f2e87ee1cf9adb70b8a65c9007eed85a0f9daf95e74c4de92f24d524decdbeab514cf1401593b15af9b7cb600edebfff0a858d2dbe871a4e66991e9a02dc9c9704e5c9a22528cb6c0e60e34008b9ca9dd8e96895edade244620ef5c1009929417f608c3188c506c06c3fa6500d86068ec1d9c56ad673a4a1b19d236e9e11b0a0d62adc205780ea5cfb8213f009f0aebaf5de6d2ff54600cd80ff205cc333ca6e82dd3792d36f637b0dbcb2100bf031f917db10cab423e8b2a6552740d047c3cc3fe5aac8560703fc1abeead000557d9e3820adb1321f3816b76608316c19ccca9a8224b263a06c886b83571000884144990089aadd60b00a9ee3b521b9e101b05c13db13bf9c28c9806d544000982ceff321c0a6bc7a63414faaeb9c59d7cce9cfee7e27ed8e3123d74037d00c01900145d9fa3152480d538a008f270034ea2df2852f3c0b0f2286f665fc400b3b44709034bb1f92dcbd1fe5dd95cbcad937d7fb81673df416fe085b6ed2d00fd05bf10c801a7f7d51a05bd3b6cd8e5f7d06b3105c7a1a366aa18dd9769fe009e1cf63139685338b654cbeecb0e0c4c8eaebe67f65fce257f6e1ea424848f00ff6ea04bae307d83c74ba29df3474b5926535eed2bc1d273227d04fda5365c00d4ad9a5d28342d4560fb813d0c0f11762ae6624470acf2dffdece5bafe19ee006b0f8fe93e87908911106f1f4245c4280bb0a62f3e6864a50e439f717f0d30001702bfb62449ef8bcff3cb60af28255c9e794321114a28c8baf820da78c5fe00c03fc8a86e21924e74af5c52aaed86684c73694b101806cbc5b14accbfe4bf00d2e127745263843ff589b29706bf13638704d7313356e7348c9851d4fe4f1e0011d8db30c9a1ed45651643d2eb7b564d427416d7bedc3023099b153d5d53d7001539a4956934dd315d8e816baa73536e5254ed82542c8071b87d97f5a902ca003a7e7ed0a82d6c4c3004fbcc58e5eb74c7786811b90cba2f9c2abf986aa0d200b047c3526bf6d1832739db5ec43a2299e1f4b6b8b7108e4ddf51002f76a64d00ff7d7fe5aa9d936489ccf307a8a26760afa9a3cec9a65479c492738f41013200fe07ebd67d5eff46c7cdbf24fa3a7d84dd767837ab99a9d0715d1a164a7b68007cf631f8d2517209e8d5dc8a3e131ca3c9e0a7c66dcab8434b3ec354e5ed21003ea1610a42dd223eefb52e88960896ca69180a25ce5167da059f61b3f0ec4100fab62eba9b566dbd7aac2910bccf0eec0b3bb3b5c04462065e3c14bfcadd760047023bc1f7dabd95fa6c6f60aa00cb1b21abf968adbc07767949411af6cf630064fba2f9a83319184062cbe5f07dea0620e0d42fa645157cdc1ef1cfc2ce380058329a59cd8d908acaf8284dd70e3b8ada39a0aa6db1fc9c20ee24b54609440033fcd8ed33a547db9d36f427ba731896d88a424840250f78ef9a074a416df7005cbbcbb15ad219adbde6c2fe5a3ff507936c3c4c95de36cda659afb576299300647beb4f8e59cfcc59be688151c02442f7c4ec5090c1d75b1b672ab07818d9000e8ca52ac9c04ccb96fc5c84ab54ff288a53c4a0c695abaffd0ee23ae8f1c000e64e0c26de76de4a31b0f18bb43b4647b92b934c12425930372cb9964acafe00f47abf61c99c324674446ce4005b575d5189ce85308614e15b245c144ef1b800a375065443600cb967d504ed25e11e3550962b5adf0c5031bfeaeb167f35270064d943ca4964a0f762c3fda16dccdbbf2c7081adacc73fff07a42e7961663100f504512e26b4207186a025fde4f42538976ecab20c46862ce394e72dc71abb0000990e23631d228a7b6b12c1c412ed62864daea2764575b065a069b0b9be0e00fb76f6b645bc1a77fbf8c3d8d3c80090cd5728067ff6d85701c170e118b10c009e6ffbe075e4e93406b3a4f9ded691eeccae9e7a4e737ca06116eee8f402af00299e12368e1ff422f8ee9f1d88fe06931e47a941eb3f2c2ad076d015485747009a3b29e80f14b128c877e8bc63ec0f920a047f670bda43cdb07c126055939d001aa78ae2cd0491578eb50bc138b4d0aa65d463ad755239c5cd7de898ab095200298d6408b05115a841f8b4bc12fe942427e1487e806a5e932768175dc94415002454a831b4dd45d30571f6f035bf292ac608dde8a6f3d4fad941172f5735e0007fd32b1beb7f3b338f107151c3d058440b70080d7006fe9eafa10bed7728bf0057e16c05273741f6531bb89d2229932b9effbad32bd83c858a207a49ee9d3d00b8575e1602c906c98bb113855421633b07424d83ac07f7507e7f802e1c90510079ecf32949b596eeb49900ab124a1d1a1acafa93af5169523c91f808f6a28e00596cfa20b59eeb0bbd464cf14d23eb4dba54a1eaa4fc56d7934178c5421f3d00e4c182996403a6df315cbbe7319975dda0869aec58f4fe7a6649fbc39b43ef003e09d5e3a5a2c6fab26353086161bd421aa2dc5cb2e43232c23a2aa479e3f4008c17e962ec32cbb84af97164591b08d87756e7a85b89f53dba86e73a6c1e40000bb00467bd9969904de85c46d9af14ad263205e384fa6c29161aaa869438b3002c9fb97df0779e3cc80fbd6ba621cf7f75dc52526af5d133cb73589db66923009b4c8907d66e1aac7836115b4ebfe99fed3877ff0db0484018ca739c24af64008556642515ec6f009ee2e6f1e5d7e42342b07391ecdb64e2baab59e1791d440062f6d44da595822dee1a1854b6b316557a215d2774145b31e92d6e771645ba00dc6fa0d39caecb6a906dafc25a697122d0c338e00f844b69da013b1824cac400789295736933ecf510444dacc5278e0b5db201081699e916fe5e61065c2a4e00e1f8769240973717fc7ca685cd820e43800710aef671e03d342069c7217af700d40d4ca1bddef8a55a780918f91af32445233af8c83f72c99dc25a18e2498d006e5d21871307070a54628327ba20e31e902fefcaef6000ce659df2b73141d10010b74584442a0b3c1bc69058ee45c1cad995158ca20a390e9e08fce141042f00bb7e5380359413760e8335a754e0443da3d399544f56629634ded890c1894700c725c7b4ccfce30e60df936e73b10d1b867640fda30254cac0bdbb3f672f4e003319d225ca3df26bc6245e0676ce4bee48961446fcbb93f9abc48f454b3e5a00e75c66b67c65bbd7631610f01c42c4aac72f6fe8de289a034f30265e56a65200db7923e7817f980f53eaa2a4b8187be8bdc65c6c79137561061809afd92fbe009caad0264cc70855f2c0bd66b8069a4e68193a3dc3dd9ea621b58b31afe31300797a3cab42041d51f428d9dedd6051fb0d726cce7faf754771ad9da6fc4e7700cfd17c2a87f1b1df071e87fb9e3f928eef4bbe9b5e37887e99bbe7144711dd002a34b970200325ee2afd15c16e1e2d361ebdf555a86ccba54eed8392e8aebc00d025baf457bf0c912a3c5d0117d7d5b06e64fc51ef3d95b5dfc42aa4e226a600ea2ea124b6150389d7e2b7ab4bea48090183f891bf048c384796eb067b675700f477cc00552ca9984626292865b4c7f21a5a194799285e5db6aa1108c430e600faaad6605339e19190903e48cb54ea44da85e307f2a4a6dc6d60dedde4a18400ac1fb329a9d4004d1e038bbefc656b767b6e7de5a61844ba4fa18bb9d1481600bd1bd68c05974808155cedb8154cafb635d5376108ddd3297aea4e77dce803003bac0814dcb25dbe17c6ba75e5f14549a08d49cd0a7358601e0b74cf188a06007187d687c18ba0d0fbba894edd4b1f72b57c3ad430a718429b39ec7f895492000000a3a7a863da78e83f72db643da3b42ac8838c9632ce2f95ed881446414a0063df23841c8579ddb8f2c0db6194d12b8cc76670a7919cdf8de2a00c48f0bc00fa5cd8d9fc5af1f526c83fd04636f3c42780f50ad0a1d7a84a71e8edee281200202ad0f6dddf699782763ec02bb90f62735127d810f0609f334a638018162500ecdf37abbfcb4610bdd40e323a3e99ad058bc1bdb4fa867f66293485d3618300a121152de9b05c48c90b8afd514f5568cacb5f6969e24b022eadb6b66e69e5003aef5e27601c00f8b0c88c2fcc4b81073eb3ad7d5fb9597596287e495bf4cf00baa738b3dae8de89e8893bcc730df9b498cf51bdf77ca4107952d8e83f0d4800859b35bff99d0b208307507396a7f28c3a879ccbe4fbfb368fa5ae5b98cd1d00efcdb209729238a6fcdec512433782f112a76c72f24d427d2bd78c14f6efa90052778d6b23fd0cd1fc1035ab564574d2ae0e9a51ad597449257c077d97119000b0a12a8d9099bbdf0fc8437095d39eff60e7cdc032d8825af63ebd21713be40009b779265e91b4afeb9ddd4c0b61484adb3c6c30b164028c6d1e2da63b9e5e00c54b6b3d2756f89cb4841a09e8476de0657e6cd2ae89bf28f2bdc9b0430e75007846c923d11526deb829cea5cf8743ce8989c28af37c91922d74c1a86c522c007a02e3108816e68c75085548e1c7bf61b820f92b215864fcefb65cf62123cc00b17220c27fcb512cc93243fd07399e98e5ba08219527de53bffe6640cd7cc600bdd12bdd4521515701f18fd9e28ff7510446f273cad86ae3a98f2e21a6711900959a27edeea98b38f1109792d23c88a37541016b20553e03646e183399e542006884c3023707b44849c49536ae9717cfe28f4f80ab951dbbfc9b1440fd9e0200483914367b47709f48a43bc5be69af95986d39c66955f9876c624284ccea4500c3bdaa9c750196a58556c16b831e3e1405970a1394bdfe6531705b6d2a13d70091624fc3821f138477dbb92008f34c58750d86e3671d9e1043f6c2cd585f06007c712f9a1da5d43e3681a7ece7e7195b4752eb8f26b946c59f8e6abd98b09100d82169c901fe66bbd7e4aff0d7a50d66f4a9c377a9390603deddafc75938da0038fa087f122e0e11598224bb86b1b752cfc20910736095c17cd3ab0e43c6800033c2ffbbcf8fa696a4b34098466a223b9b47c487fc4faf09138b4b2d4708cb0083c3549f3d5edd52f442cc209f609ef002cd6ee22661dbe4be317e5b500bf800cba68885de0a9599f12a470db197070b43d68fd9d0b01871b65523e175c8f00081954ce1145981988fe4a54ce8b8bff331b32480c7d549910fd05e7fd2fd3f00b0f6247b0eeac990b8b7366f36bf5c53bfbbfa84e55aee0fab9615a7dc72a000c8e5af68a6ae75c16aed8c54991914a2a58aff2bc011ca6add8b0000e351fa0091ca6a0026884a361d3b788a4275bb05bd3d2df031b1a25fca45baf8fe5f0e00db79809fa0b05d46e304b676238a0a688004eabb81ceb5d04d4806a654aa030070fd6bc24a7160d888f722e8b155e219f06d33507e8acc7aeaffa07a59e809001e8ad71168e9039a2d55223e2cbdf97500355ea1623fc44034d1bad29215440001f273ef3fefee536fe41a1cf784a8b6131963cb06cd2817c47233ad4cb71900c96b76f6ffd20f257f94dd31e659052ad1997164cd8e9648b05740ac4cb09f003b265915e20c0b09c482eb9642d39257b7ccb82df0e28c67268702dfde1f4200e9eabf3b1abec7b1d60e83c3799c8b605eb24b6a153cedf2db969aefb46a59007e6df7de6fe3168dff0ebcba754bcdd17997b90c36f78feb665cf404a064df00bfe3b561810138e7b2c169b0cb094d7710e6e47fc4ca6b4d4cd4ed41701bc9004593ca6b5564d236981547b43c695637d959bc32399531d57a258a0bcbecc1007137a1deb17f4c1fed10bd2cc8fa42e01c87496a9918cf6fae30f960fb4091005ec60a2d31e2ac2f05223ed10d91cf14b62e2ee7230cb315ca70bb0bcde3d10057f6371680289db1a69265597200e6239731874eb26b1338e14992cd01a4a000b640b2d4bf063d18727ad72bd9d68bd25a379a2ac9f5744f0798fc1787434a00893c98d635c7bfdf660c93b82224e24b9afe413846823f24a60d4ea4c77609009fbd3bfa4542f9fa20393c02b3d44666283d5ef17b5233fa5d117c21eb4e7000418de8359eb28aaf6829f1988001c5461ed9bdb7db2d8a03d8545b3adfa1d400071e1b6273991c4ad7936bba8d52658a8ffb93d469d38b552646ceb523c9b500f3c3a71537b47a7797751a4ae5d1707f4c27e5e93ff778a11e2aa7dd4ea250000882c9234e597710bcb71b741247f3fdb316bb08fa4c13d8aa9bd5af90876b0057056ab9a9d73d4e143bed5e7780c54032695bff78e3da7c66c9587b785f9c00541ff2ce7fb0e4b18b90582f0c2d20e94573a74c62ecd959cd061cd38330390055b64f95c6758f3c67503b099a7f565ff14a8c04546bd76934a40bcbae75b700b5aa2cbcc784a7c5e30972c1ec09ef0cb4007a7314befeb8d2c929fe79bd41002e870ce65370a29a3d01c7949b54adf31d576c58163bcd0f12a466de88e7c400b22356bd5732f25955b56764cf47ad955e496736012cf217632829278f3139004a647a898c0303ebdea80745a39a421fc23636de223135325fba66b9e22bb100bd2fda3778970f410405c6abd1299fdff9d55d8678097ac63f66cc2adfe09e000159415f0fd4bba82bf210d6e7b427e6fb64b8dc13f1754882a2dbb32f998b00e4ddb9929cfc6dbbb1f4a1281412701da452fc635ce8b031686da099e5d97000c68f6fae7d7f01fcd462765aa65875b7c5d425feca92e983550496c38dffe500bc4802f8b19050a72eff3dec640b72ac4005bcbd64023c1e62ccdfc22833e00041c23ea43c6e93ef9ead6fcd4ef746c989c43ebf1b5bb1193b57c9546c129f001509e3a8563f053fa57036bc9857e41ae1e7792fb43c29c9bbf6bd79fd66230013c3e208a07c2eac524def8656a1424caa88689fabaf2ec1f824a026143913005203fa0ab553a9ef3f9be49de6b9d0b3c7cde9f4d153e712a7a590d54454af00fce73f62dca5d4a79ccdf2b0083d87dbb7e0ee78506bf2165c2ede1996b3e5006f9fc915314955765ae4fdfb56f1a7b7a6c14f737bb556e66b31a2a2c390f000b9c93a34177b485cba0ca422136447754a7a58d499fb95df27963cd103183f00f12fca5e1dedee1d77e8aeea3b0c688e63446f6497ad1668f840d7e0ed07a800ef45d493d25992904634d9bc1aa63c237ff047260ae8303a88cb4c2b5208bf00b6413601b31172170032484e1d1fe5f0faebfe1e0b31bb5c803ce9869655ad0012faf96f782ab51ffec48cffba54ef4cb89fc7643dd4001d225169597bd7b2006b106ec951b8e43d38da0d7b34941a165e8ba311e96bd44a23feaebff6fb54006e38b8691872d6f3b159f1bc383cf6b996129995aa65b416d16dd8b3b462b900eace14991d2e58c9cc957e6e043a5cd6cbcd95c9aebf814ca761286e874fde0095465fd9a7951cd56dc6b22e9c403cb2d75c39cb030df1c6f4601fd4d284880060d4eeaec0784514147a0098d28ab9e48f96acdf8e0a8487596405708c05ec0024e4cd593e96fcf663a2e8e7c23f5f3dd054122cf8c3260b2fb58bf93a157e00e6e62c41666e5a5604df019dac6c49c6dd1bbec7e39095a878408069532ed800f1f81b342347e8ecb7cf6b5b31efa39f9c5d8ee38fc127b6adccdad77d0b9e004dbdbe06f5b9e8ec5d6b184a2d81ad5bfd1560a454aead87e20749acc5dd9000a66d992768898e992f99230eff7bd13e1c94a94a92f68795164ab93dcac8fb006480c9413244f089f35e8fb71712cbdb774f46730d4caf317cd7baaf97239100bbbf81c7efbefe5e059067712b065685aabd9f3ee59d76db97110f926e0e7e00c76668cfc7fbf61ce7f1830e28b88ab6b7cb332e3520495e3f2e022b4418f7004a428ecd8a69edc2363f4d7f3da4420f4ccfd00a7132b5d0514e20773a1fc200578a173eeb6d4260508454d53d16b15fa9285ab47a509baa9cf1a4d8e202ab00cd01e3dc22f9d40e0e321cdc3cfacc1178c68bf4baf4105b4f2f0e849f563100dd5c6e526f2788eafe9095fb23288e489f648cc8936182b15d46a69ac9b558009fea6b762ea77e0970f98d7b4db3ce032722a1e543c06d6a6bb8bf57b2f6ea00c34965efec7367bc26f8dc7b66fbe0d053fd87b60002d4554f4437bddd1c3f00d9846f0f11d41aa3581e78a3475380acd2287d68ddea2072950414cc2ad73a0037d45aea2eafd149493bdad64873049aeb5281dfb288d9b17c71c92e9394c7003a31ebab6fde279a59e0cb070782db87fc686e070e9d24bc3da179fba02c1700b8948150e3a74cf4187a1844c8c70dc6bff9a6e8d13916ef85bfea278d9a0600fab6f9946b6f1c40a8a7f270539a05217c205a126ac8624b00ee016bbee0ac00e54537983330f525f7585bbddcf5caac45380d0b10ed3aefb88dc86442d6d3001564fc928365209dc55f13f063c93f2b6ca4a2a9c12cf0753d646c8e10c6bf009f1a783032a447c943eb72cc659116631e9332153640df5ffbf7c6713484e500d66528a6b47d81da6248de0d9830d71143d29153aeabf99782810b7227f3d7003ca6556a08e2e4238c9e75c4f6ddea0e81facb516d62fb44d561983399410a00fe6eda2e5d5e156a628d43d9e65fe67f468517468f1966c5d3d52ef098c34e009e12c2d3ccc20903c41e49f4aa99eb3a9328d7ee6ee12939634447b6bdeb8f00a684e6b618988f36cf99c7166ee1f966c23b1b9a8f3d81e0abf6bdf2b7619500e9322c94c05240e4e04dfc799706f9375d8ccfacce356cb6c3274c09385a3b0054a6348b03dec7f81a756f2a52731bf24846ae0113ac41f17ce2d68f128605004bc73100cf3f62e8dfe51ab3cf93e58111f38f5fb7e324ac2f004f96f65b3b00335c5cfb4abf4c690c9a8babbab1428bd0a5cba47efcfaa882495d9144baa100ffe5a932a71f493a45f08fc9e57a6821a51452b8b03eb66cfe0f7bfb44bf0e00df801178257289abad6ae3b6869ce308cc2b0e39a444f8ced8c55714155d7d00bb62c281ab3ba2e9c228ce1bfb8f98cc0fa7b161f669bd642de113e55e354d00f051b5afac283c1c693f1f1f666fa473fa6ca32274425e8033978ac2c31a53002dc1f90ab914f5365247ffefec103a0082e8e27c2ca1fb7e89c476fe0b6d95005c24b8b25e0db2c87e2d428baab9a926089f372da9e2cb4384cb9bffe2172a006e8145841c788bcc3b24792c579456c619394fb7ad47a7f8dcddc58b01463e003627a67a691df0d0f483c94afb8b93e17cdbe2155ffbfe6bddcdeb6c3e6d9e009397c41cc5e1fce827dcc5a94cedc653c4566489fd094b4997314713bc9c01006666fcf32e0bdd8d6df32357eb102c158e84119483c3f53fd2b62e6c966b5d003a05e5872fce5de6524914c524025da20d45b5eb4dd23b51f176e9fd42b00b0037d72770fb1610166389890e113bc4d1e99901692da05f3161e7103d70e3b4003481c75bcccf5405fd82c145bb668fd060316d09305622d90ca2086941c8cf00ba68f74cf1b0a4f38e96d94ba07840f42b95cdd3da85cf395188a6e1a07dcd0042ae78f5e4923fb5473dabcaba44a4b580fbe77c0b9d012e36a298bd6a3a720062f76d0f6a6687eb985751e0337ffde33b84b06ec7d45027e3160f82690c7100b330b46ca95465f7e409e5a2108666c134737b3db1f0f1d952ed0b0fbef05e00f458525112f8a65321c5c015d5a7ed0e63fd51f8ecc6b14c6262af6043d55100bdd1cb8e142ef3379f3b7749effb8ef673fdf59d730eb062e12e96d65f6e1c004172ad92e5139cea96d9b453bcf38e0f0428b77017e88e88614f518e8c7ce500a827ad889bcc14912bd0c94e9f20dca92747d9347642ebdec2979be2946db200bf6170e7cb7c8d897bf5de8123f1abeee5569560649a5e2b04b0cb2f6a0f9000bfa5cac2a2d860e1b0ba4cfd427b17f7fceb8064cc5d673ab42ed1f46546af003739f258411d848cb8a5d194efe8aacdb5da5c99b6da8acb7f346affd490c3007a45d12083425e4151ad13060777d8eeec438407bfcd100c1f66d0dfbd938c00cc8c64e39ce272cb6ba651135fb54a1bd9d1093e585b83df030e545d29507f005a44e802b80d6f611d1b403c74f42bc299145dce61b056ea95dccfdb44bfe5002fdc0b97a9a9484af8cbab83d3d798d53dc556bbe2a3b187493e853a35245d00c42ff6e6fd5d72a86fe3ccc44d96fcff85eb6b73c65915ec58e9c577eb966f00e78330ddecfcf30d53249308619e22afba0ede2ddf6ed8083b32672d380221006dac89cdcebe31440b76f20ce6796bd5c6627dd35c41ed38a460d12806e5da00665ee6d812a88b77b0ef89f2960da7ef10bca0d045176d57ff819f254d9b4900ba4dd134e3dbfecf932d8b6ac35d9f5965ac6c283546de0ac7e26c44fcbdf800e071ab6e986048878b077d0789721448467a6866fb9bf24188a3b4f0bb4c42008edf4ab450d3ff76269e8f6090c0adf5f4971b6bf943f32608b1f25c027f250080ce78b5b3768c804798a8dcca9d0b7c423a1d29a9a135e07e455532c83168001c03c849d093bd3e140bea7c177e84f0515409494bcd920ae83862fee7dc9800cdfcc95b9c2ac92632eac6177be3aec9b591c09907271730940efd081b009100d2eaeda7c8b659d788fe32abc16f953cecf97b096eb16c5bf1dcbe6821b8a0005ea92edf539a60b97560f0d439533a8c4d6a7752dc155985448d02a54b2071007bc53bd8760f9cdc172d22053724498ec83e3de881e3a3cdca00841f90259b009a451e7734d00484babf4941c40a20b9e593a9c3213a83037853206bc4ebdc00f9a3a7ed6ca032783bc7ddf8ce638aea1cfe615f0a1aeb661271aacdd1c849006ada26b954b80d2860ac6c791b3e71379b5aad63d86bb456001dc704f1339c00bd3370be22c2ab31dd3d7664c88f479e4a5c5ca289450e8fa24aeb1cfcc5a000de743f76f6c5d1584cc00d9159857d047327701c2bc6bf44f52a36545b1a7500e4f282816622b93b548c55f88e67cae4f9c49d4450361b600030d99d2c957e00c066891b9a150087e1f4bdc5c9c3fecc2692f1b914f7c384fb76917e1f8155000f59292a3ebf1f23e5906881d6d07867e1a035e3b8f47772679752a1f17432002785bffb56db1fd912f560526a0fbed9f780c89280827137155f8726aeb38200dc8a14ffc9e3488afff7d7de0e84e228f2b7b2b44b1cf6e3f6d206537abf490081701f06ec57d2e3555640597c13657da2a7d8929697b872e006f9d1e039dc002f576aa23c1f127b51e423e198aadb3907c1e30a24f74fd150a7f33af28b1900b911ae08e08506e1eb59fd9e96d4d8cb1877035054ff26570e651c9978612300ffc1d2fc2c028f0185fba7b31541c93551a8afd6d5cddd9bb9554ebc9051a100384d7075fb8b3575969f382d63536648a9eac2d9f3dafe6c77f92e9f0b457d006ae1681ccb19a2b8b68b312c623ba68d2a5f1a6d0dad8fd0c77aa45dc1db8200feae0a72560811fb3a87edf21dca54cf617ea86c7933dafcecadb90c22b389001fb3c8dc67ad24663ab17fa655be3343126d745569e08ea420c8c877deef92006f3988de8f9d80d3c3972f69dd5212d5958f9ca043714b99b93dd64721e3c800e43e0f06f2a69a2dadc8f8f4995a76bd5ba5403f32f0d0f126b1976d9001ab00e04411d26bfebe83d80d18db055356a5beeec5a0e39aa88fd205dcab63c4ee00ff700224d2f0c39febccacfb2a916d8a7ce21d99413568820259edd2ab1d4200344730bdbccce14066b421f85f7704bfce5e49726f03b9f110a8566810ca88006703fac7e3a371a600bfa6a9500f02cd4df053d6b77a3628eadf8350d4d885003cb0b98c41837096753bedc3594ee21dc721e927717330fc861b3babf8efb3005d66b760840036765742a63d136c3a424651de3456bdda7c5b2e301d8ce957006706c704857df9ea628f702cc46fd5a2a64617b760bd36db8a3d3fec27affc0040e080b531633ecb0f4ef0154932cea9118b563006a7d78c236348e90574980025c1b6b8b15a1d66ac0c924d95b127ebaf2089e1a7253f44b29eb4e95d3c5e00949aa41e615a0e3010b719b3c335dc6202a752b9e2796d06aa6cfb882d7776009e8abb909012d91a69aadc20fe5cb3a304181b92c64c8cdd3d9639047dd26e00aa665a1ee003ca4849f2eccaf987fc95aca99d686c7bf12ebc67daad778c6f002e6797214607380826f6dfc2b51ea36f78ea23c7676ef3bb9bff7ac562f607004b1ef52886ee9bf1befaa5c6036cb4e47b1b22253f9d682a306c4859e5d1be006a1ed95748d23ead1d39612898e5965032b2bdc356e00bc7e87f442125812500a687e3c92c2976440e86f797e7c5ff3463ca832979b7a1d74516c55c2b0c6400666c78e5e939329f25ff6e7e3d90e4cd08edf251f3b6b1104ff9d3374c3a7e00d914424cdd9e428373568d6d176f99d5d8df6a7797aa29e8a1558599429b48006c325170e2100728cf33cd46c054b9fc599d0aae7314fadd8d12c141e1239f00c701b567bf1306571e0a92a99dadf80daa50a8498a7511a4d924bb7a83418600c08fc68699c4f3cc8d636da425cee18aa3814cea9790210389f17598d9d76100f2af949380745ae7265ad9d628526bcece007cff9aea2e40173ced6dc7f63e002384e67ab6ff454efc8ea55a829f024b32898bb8213a2ded2b5a58eb2ebedc002f1f5729b0b1ee3904eca8890b32bbfaa1fc36b4beb0472bc2b393c42b2c500014cc932acf9321682e92e8d334ecaba92cd2bdef4a07f5227a4879e34f2a2600c7c2c6f8c73f9f4dbb48ebaa0bef86396efce39aed077468990a9fed2fa12600c2ef2f076ee7dff0a054425ada0fcc36b6389a5ba07e8afbf62381c6023e18008de67f59e58306ab748a6ce181bf5f0aed4ea5a430139f8862a251151bf3210070a16b08cabf2d08f5866fb365079370bda646a83bb71688fb83bad6efa98000118423bc38c885593e915920c4f025cc2cca9f3faa90cadbc668c3d5d002a800b2acc187c86080d8990fc19f7161b23ce34cacb6117fad3dc65795df117b1600547bb7fa7229eb7e87da79a487be7fdf7648bff7e4765f9f720cf9309a9d2b00f57334068f71b507c99618900585f4f3d0ff57dc11d34b23514922c9292473009e4e6e9cacd6f630031a15a90c13612b9e6137fa270536939014c211da3e88001fb90d48b5b2ceeaa733e6d6b1b266e1b91b132e25341a0d020f8f138c7494000ce0f1893d6f5b8b031c1f2a6e1b7e0a7c2a735cbd881fbdfd0d3edad1b95200cd5dba5492413dcca832ff34311bf4ab9c126eecc75cae24496f03020c4dfb008f62ab55a9b20cfb8164ae3a8d57d511852c8b972d2459303c16f33c8e01cc00d1ae6d0c8bcbeb64372e6b620915ec5ac4c923efdd807cbd22726d522f3b7e003fc64738f31bdd28b29d0a4bfebe5f43ecf3c81a9bad3b79b39c90b9d6647e00c8c840b26c0b9dea2e2f2407489e51a820a0d5f3c0a73ed4ef0a70b24db53700652f208a2fe0f4597e0017fc9269d78e1e787976b17f1729c1788f5b75cb97002d29f2ea824220980a723d860fc2b4837fa47d2f4189f3d3201da9e8802ebc00c53ecfe0c69b59bfebaeea9154f935ce5fb4ee40d6420d45ddb755fab2074d00688308a48275e258af25821606ef2cc12f71ff4ef58d2e7aea7f8a689e928200f45e0266957fd33f0820b249c7cf14c908793bb2d7161fad30b71a3f34265b00e10e1d6cfcaba487459d6b371e911635b457e385638063cc09b3729c9b5d52009ca026fd5203dc83522ba3e99f56727735d677b209b15b631b1267ea315e1300377a63d7b414a5fc69b5dcf6a5d3ecc4fc412d43013bd2260e10eec47d7338009775b62db9be77d7b771b24cfa3236b5f15f86754842c0bed9a28d8d046f23006ef9809a794be2f81a56077bcd887ed1d2f9b59e0cafb3b69555d5619582a1000cacb7ce15be4cffbe4149f796d61bf913209664a0e0cc0dbedd46bceae865006c960728aa8bb7491ca30cbe97616aa3e6c9730a841694afbfd645199608d800dccb8c3abb3bd22806a7d8885c6a1d7c893c314a2687d83cc27de581e608a300ed9d013e7e138063e9630457786d087c15791b0ec7f0701443b66e86abf16100fcf295fbe92b053d811a6695c0757fa5aa1c8f33ef42630f1496ccc2dfc10600bed501e6ecc40f9918bba90d6fc60532019a435530be257a5f6b64fec744fd00d0aed0f91651d598e870d6bf46057bedd4c702d102adc422c761f34b42ff78002db982cf30904b855ed1645cfec919f85c638389a4f416b48af8a765b512f2008a15af1d72df122889fe622675ec5285996135c8ff80bdb78d60ebf3db0f350024ff07ae23285f1e98a16cb2af0da029d21fefde6f9335856d650fc8a8f3e8003b841e4eb64d5ffb30246cfb5972b549ee6f991ef63539df2f4d3c166b074d004a192b643541e55b97afa4a8b60b86df0327471295f7708527855a87552391004f99ceedd2997e4c53c4a01fb2513f9805eb5ffa1300bd01ab4ec270afaa2b00d9e5885b6c924b02e073f98d0715312d671a10379737a346873945a428488100b8eb896fb0feb2e7bec4432d352de170336146940858c5838b659249b493ed00d9a01d91698d4b7b0e2ea69a997daa87606430905eb8e415b209157b2e3fe0004e3d11a609fc79029a64d146fe4b83c1fb8f02c73d75e84047f799879482cd001df17f03b3a5c1beebc3fad7d1e6f24558895a8e9c1b41ca3fd82aa970fdbc00d856050fb77392fb62ab27a580cd1f1defcdfbb03f2c8be35454c915ce107200e0b0b499d040b2895ec524e8cd535cf577bddbe634b57b702ecf3b5ae4b9dc00ebba7c3fb95dca8fb351cf567cdfcb733399ba2d96fecfce0c62c55bad5c6b008eae672aa865a51eaf64f59f86acc50641b73714088f7a6894b57d6058f6a4000243ce2fea334664c71ed1b3d89321bcdfb0c178be16019f3677b3625beacd00363835afc64c388b9836699c92ec4591f2f2a701e70c2b85aeea902f2939a2007771835fc4d0dbe2b5a6cfd40d93d0e1ce3a0f7083dc35aef07a56d452c15600388f7ec91c27ede5d40173fff27aa332b47d6fbce5cdb9469a00beab78afc7005346a0ff7fb7d0ffab01f037ae21941cd1680d622b8c7cebef7764ec7d9e8d0006ef2b7f076ab8d74b76b0b63954738062578aa244e9a7ad5a7bc092a8a42d003cf680a26c16f3ca3bd91a1d3a643c9a0e2976490538f79f1652b492be62810055cccad62c95ca83d77873d825a93dee6a3251ef3c979fc055d044723b641800dbd855ff7ed6790bfa54dde7a07fdf037e64f72032a920d043684b5a335291005a160da2136a2508c3f5dc73d250afdb6c822b79bba4477fcd130863e6787100f87616417346101ddea1865c64f0ebc7c0221359d4d4a3cfe27280ebc873a0001117a6dd890db39e3bc49698b925f8569b314c64bf5abed7e9945e97ac0ca700eeb4435f2bfe268725c0883e1a12ceefe4eaa7129c06aa5ba052d6f055c0790099d0144c608f4f0fa1fd702745cc29790ff508e1e973aee5620676d20089170060f3bd6ca75cb47f9b1df2438ff4f0329cd86cf18cc7d6a4721dd26fbf2cf0000a9d597fd0e23e607eacde8cb42d8be83351573eb1b0e679318f1f674db16400527697ac7e7891e2e8404e8dced70761f0c0ebddc2755bd676ac14037d874a0066bf2726380622b874e8e2caee3b7ed8d6eba8543145531f4fd4c74056302000ffd4875976089d513f63581aeec39c88a30695376e903775df88094d0bf18a002eb7027749e4f615786e461a4400607d26fbeb7c1be48d7804ae5fd4f6127d0078eb8932d153696a8b4baa910fda207629c7f91ac5016547255315117ecedc00a538ff07c4f222122ac24c52fe85492cee229ca925e93caa677110bea948c700407ce0ba8041ba5a91f88057176f24f46b086fb8cdd8e01dfc207f9f0027fc0030c4c0a3e22b43dcd85551156c5adc7411709b23e6877f260610259897e0b300b6ee1cb8566cbdbb318d37a3f652de5583bd799bac974290a86469e6c4f47d0097af5654c1c2c665bba3f1aa05fb556a890de1585b12bdb7228c9ff6f8c4f9001f96ad12d520581cfefd919d719d88e4743d58d3a6611d5365e4bfccfa9f9800c92f961edc3208841ae971641f24a9740945c0e8a2ecace2c0d06c335ba998000f16c49a923abe10a0d7bd7f08e89503d5f15d46694e0cb56ad624f8e13ed900d4db0ecd7061cbe7a631ac4be746b3a4e5513db1d0e986a64829fd143d38ca003cdecbe25f6324cf37e54f6ed8a7c2552db8c1c34fa08d9fa79daafe27d7b100c4a69ecdbd5e8253d6598d85830e66f75b753f721da55310b68c3f8cfaed67003284f11ba4b773bc3f5844469158fdbdff3f1010aae9b4670cb3097c0ac3fe009f40ecb528658284ef2c0dc883c7c1c39d87e0d7c56b082e118dad65e0c4be00085f0aa88bbc383b8e596233d793456b573e8d96fc621db7e21f404e98e6ae006e9bcba14fe090f16020f22947e0e67272fc9ca5d6223b15772d824358ebba00d88502b150a508f992646963ae9e2584daa9ebb72f0db3a514c312649b7b230061965603845ed9daa1186cf51e39df1776b29590fb225049cade327e08f4c100cc11788b02aff016b5832eea302bb7a57696cb451d108e65dedc269f4b194b00ac33e38c9e1605dbb9407dedf0eff7fb4caeab692bdb3cc48a7aaa591737f1001a3b6b516b0a4d1d04cf7ed3ada4aa9482269528a4ca241f93f47566bb572700a04c32563e269cda186bb0723de91c3091a843c351abe3a54137f2b41df595001c881f8916c84b91611ed8158c0a7d03c6965208ce2d6a713fca980119be5b007c0c30f517dd54f463c444dcf2102ac5b7ad3a3beda2263eb9a3853818fafd00b1c6757510fc5bdc3ba535a725dfbe730ac40cf96a26691e0f2948fc6526940079a3e57c730e6c7d1e4f06ef7f6a170378f2ef98752e7603a9ed223dcde85d00725a17e05f5d3351dbe9c76c4fe02113705f91de2a80c000045333970492aa00ede8cba47918a8f1d861a4f334a8da674c27c36b9bd27ca6a0c907aaafffcb00720d93169adedf47bd91b194cc452ae90199bc355244f350a23537c6a6a95e00ea112af39cad964ed8a0bef079a3f40c6984540b8a191860bdeaa09989b8a700ac569acc3666424e3718ac12056f7f1c7ebe6d2727d2b0211098357f3a60bc0078455807848d29ed804032bb02ae926ac994ef9646e54673b5d2fb93ee5a8c00ffeacca73dcb82594f539cc52a1127e8de3a0f1fb7fb40f8cab1804c071ec800e7e11ab3a821bb5e93b7433a6338c4fba478f07da22112a2941e097161e8d000d6ca28caaaabb794960f7d3ec812166424a3c16a7754dcd9d58cafcf941b480086b536a4f0ab0806a2b38ae6f11a47c3016cb01e52910d935e02ea50270cba0054d4a597e6069906ec01b6b677b33cc40fbc8d3cff1401831dcd6c0ab75c2c0058aa6bcb484f3bceb7654941dab7af6be540f179c29e9212e5e6c25c961f37006e47339928f670d77e037a8743977a14ebf780695aa6788f4610805f4d709f00031f0e94d985b2c46b768b48ebb28e12ac9b11c77c4c25da2a78718ec7f1930043bfc0f59c086757a3b5898f06d72a6b7d7ffee224eb5ba3d47b93814509700060b1b7e8c653006ff8cf20320bae40ea9a89b21a6d31e372e9cecfbcc9e24200644cc3b0c214cd6a1c8b31c06e86e3528e47ee24594413723e3d0b018e7e7e001c43f93a7489f149128576256071f437b0a0c7a61e2620441b9b7264e1a8bb003ea4029375463a2ed9e4bd63dedf7d76f63dd229fae0708a218380fed9a2dd00e6454dadef5dffb898b253c0ad8d8db074022d1d77dbf929fbc74edabb6fc600896dda8adfce8292ccad3198deb2916a9c54f17e8a818c9525f56ccfd4e01b0003fb3ec34641fcf002ed52c66f62e5f8dd78b5326c96985bfcf7ff622bb66600d10295d093b9b33a11475fb7a4944bdc1adba6112d6853e24df7b0ebef915700d8bf292d13ad91c6dd83bb3e1dfc9039bb29e3930e60e1eb90c9eed4a2079f0024cd75009d4c25ce5256d79e90876e664384b368df0615e053cc8e5cc1d4200070714ca9a1361e6c37ed261906803a30710f99b7f3cc50e6699b2cef7167c700b85d2980f3d0fdd492ee0519cdddb273ad51b04d610d23626c17a78f3671fa009c26494d4e75bbe6abbb480011c627551efd7a0bb459ccdf685d23c46f74f800b00ef63cd7f4f7117fd1364979772e79737bc5e379561b6e5c7cc62f78d1dc001a0329e0a40b32d3dbd94be89ec42fa5d240aa262310e8dc8ecad98c1f247500c4b0c68abf88285d5b5f8e0b40ded4f21002cf64f4a819bd92b4e24e71ac3300421dbd9d4f5a88edd54799256d6bdd3785e309763706d6cb4563bb4e4a7a11006126efd5760a6be2d9807f5c4601f1bea55e45f8001303b344962d7942647700a70c0ffa5ce359b404ec247b43fc1aea72f08bef06e35c7d67b130c19635a100496bda9638e9f65b19b6547686b7aadc5838fda7040d0b625d4c15e343606200db405b8123a1b200058bc95c8fb0225cecfb57dd39adb8a898a80d121982ba009537687be64255406925140a6454d193bbf9c16167aea7a3396466a30c745b00a0e0f2b4bdea944e38c96f9dab929c0f7a813431cda37a0c0a67fafb02a33e00e55a1e79c4b1a7d38119d18634eb32a2bc4053c5730093b681e5d55404b054004458885b20e29f8c304e1493874f4be42b3a3ea017e8c1b3ff481c22118d18000721b6ee2ccb9f133a23c85735086a5b7b4dfbe9c169d84a833ff56875956300ee6a7928c029d54f9145b5823522fa5522225e25d8867b00ce5fed73c198e000fe7fc7c71d4fc5bbad7e88812c6033162cfd84698b56b08e85c43481c4b9ed0068b53f79ce55ced311aebd207f3eda698c2ba71f69999d9d0bc003cc03880000381f7d522c5e05f3feb7f188c74c5656be992ea1f2c98b023b6e4842e9024e00d194697f72aaf536cceb6d8c5cd55c1bb67a0daa9a561fee541e88943a626f006847c319987a23e425eae53c62f225faa802ffcd210ff5a3c3aa10a982626c007710e6f81158dedbd41dfc96e16682497382e5c497113f84073adfbd06f7200071a4110ec37eea2307915a00ffb56e0f7e9441ecbe830b4e77a19217d38b3400419d53740765fc195c7a0c801a69d9138dac4dcb0bbc585939d4c3c567f48000bf7c4ac768fbc26937a357a1af8470e302e38c1c5ff836dd2a84b7b4734b230030e7523499aa74c32697cfd61f45260749265647b191d529d4082ecaf3328300e3eb3e086751bd2ea260df1d32c3251a6c24829f70d943c812e9b9454c106000b41873db9332b413402a65b95e65d626fce389dfdbc10991d8bcb3f801104a004d30be04ece71d9503a64869e234d6daccc16d520ee70fa07677a6fe70005400c12e597a89ea00cf8bb98b466f1ef060bbe043449221475d76b653f1abe3c2005e0ee243a41a5622a366d979af4d75e29c577675516988329ed3dd11dbe2b3005e4a0cff60d0bb7b39cdb10be9c1438b8e176063eb6fe69e6081f5ecb8f25b004ef35b9fda56730fb0785c6707e902d8796e2997b7a1a542a50f7dd3f7359600becad70b94b020deb40e965ed19a8c74c14ac90eb84df480a2c15e6716a30a00d27537f31ad3a6f5a3138c0b21e65eb053457e1677ac37829b83040ef7512900eab0fb622ada45136ae5bc0e3856a288d1601353cfb8d923ee175741079d4d00baab8bb39f26a1ba9525e7f2a5e4860732c98fd20b0ac38a31de5bb3ce23fa009728e1c2ebe772612db21d1019ec1d72a880328d729a2b4a324cc0f98fc6b100db12debd3b4a573bc317d76d8895d4d9df463da8505d9414935a7b8d67fd4400951efdc332865dc69cfff5acfffd00e72e2e169c36e0f4400e2b877cfec71a00b7bd96426c70ae20d93facf2f63aa54d79cd8cb20f04f7f8ac863aaadae4e7002d274f269e3f117a28afa8743c8ae1f1a0b0c3da28717207be52b9d278b482001d1fa12b175c241c7a3183b31c52385a85934e01f75c97be46ae293047a8060021869dfae9cf9647cffe884e5b9345491d5f810e34e1ee484071b9049fad0300e50a6ba2302787c918e97339d5ba78b2937818bf155ebac6b2fb5d068dd0aa000a247eca84db300f62928bfdacc7963fd44766ccb202c22dcd89530aa09c63002036d49046ffd5c6e17a66ff22daa94df0b149bfc917d56ae8542caaef8c3d00ac19c211965d15eacae35e12f09b17570e480f2d97ccf3b50389bd472bc4cb00e766d27f583eb85ed93bf029632614e674ca7ef887898ceda7fd72af5488b40064f59790d5600f60efd30b0159c844a9693f203e315b44f9f1ae9a15477c1c003a23e7ba519ff17c49ae74cfe3cdd8746b1fa921df770959319bad20afe00f00d3ecce56071de2f504f739fcbd239b36f11f3d2a7b87e40dd4936653ffbd4d0065c5c605ff372624dfb8087d1190fd95df1a101728c2801af7298ebd2d09b9007c65bcbe2415c3ab2e4afc7f7472c6fe35ada45e5dd696e4de16cd350e7c3b005f8c6c64485f9684aaeb2d5ebeb5f15f1a3807957f322d4aaab9785389707900e709ee6e2e8fe77aa5f64894e6fdddbdd4827f2c179e2548fa8e93847c1693006fcf68b24a90386b352cbd82147783446e6d4f718a05bc3e090f1ed92de7ca00241202a758b6c8746804c58717f8badc459bd4bf107ab18580c5e2109b3b4f0018f2030beeb657272552587317901d03ee5e90de4fd5fa01e30270d6454602004804d0f3f2eaa5f24ed6b24bdcdfd0ca717ff4ed06c0d9156069a06d6223a000868240c55a43832ca437543ba5779ec070ccf19f5b117d2f5f78ea89a6f6f2004551e0fb4312d1595c4a362be17434fb23c2cf4e491bcbc666f30a0e67e53e007020dfe10c8a1faa0ea661deddab19344197c3210ec06a383776df43410b8800a2ab6f492096e9a55a6475fe005e7c2ed834f77b876246bf15e13112089b7700840af4469f88dcbd999f36c19f2e4c946d8522c68e3df531d18f1dfe1ef2cb00e1c3878986f2618ea36ee0b176a7da619a9b464f54be8cccf10465f810644900718396bcb6e3bc94c056449ce1238e35edff6c20b3118d6c76d342787bdbd700abbe926aff8b968d77a06e73b7962a55824c9a2e501bb8580e5b788030d97500199ed467bec0ff06fc0ae980875269a8e4189b24363eb650c56da5305cc661002ffda40ac75e6acfa375eea5e8566b656cf0a3e71e1bb602a72900f548bf4e00efc594698f0b7464397a08cc5e054db7256192e6a8d063ce6914d6d43f3e26003dac7c7cfb25d24aebd988a161c3a424969f6a175cd921cc62d25ab5b5dc0900443c71afc2ea27825611737403ea4589494221996f7a7def5e12ed0d26e9db00c5084bd4d09ae051dde2c8e7d81cd5ed36d000f724226cc1b72232bcf1fc1f00d4f29bb3be600708432ba63c84328a543e143c556a76d6e29ec83f6d3360bd000a603583c0856b370a9b5dd0bd6bed07c701db04812cd3413691aba1d0e80400df0dc981b937ef205d21932a4a52e2587278d447f6e1285ac21752fc82a204001d929bae77fb20a82dee53d2596dcc626948f3a7f1cbcceac47c1ca9dfa87c0049676a37122b81143520f2ff0334942470d5132dfcad11ae5c5a0de272ccc000b783cf69e2b00523f3565950e69a90ae8c6bab854be5edfe2e80c5a2a0712d002ca700f41c66cc152857186196f70195d71ee5c5acf55f8b2271cf348b4a8200c6adc11bd964e52d6226aff543c20d66e6adaa232ab80a116b99950cea610600fceab7252095d25209b606075417f5e4e09231d046da9bb738fbae5e7988d200c564ff594cb8e2ccd5655c2b1972c5b8ce79a23dde35a98ca38fdd37545227005c1dedef9814d88e3472cc72671dd6f0470e16438d95d5a32d2865a0f474a50092f11e9e06610874ac574e25743913c85ee3f49b9c447feee39fcebc1935b200774b22a2f6bbec6767ca9d5860428e278b8dfba8b1cae75a191459d8eac82c003364567878ec613e2a97f0ddddcc8c50346518a82a80d819aa0fca015e7b47003f76a2a6269e61461de82742d3edede771157ee9d064d52f7fbad8c5bf0c1b004a8a7dad5892db609b27958fc9bb72722334e684d931b7f2b5dc72e496cab300da33c812642ebaad3cc1ae6afc165ae50921162d4a3a10f1b9f19791e3b331003bc812cb27b3f7a3a6f661d18c3c70ab8d73a0a368ca0497574285e945e9f400babf130c3380aba6f022b8e452c01e5c1a2179336584a3fcaaeb6af4ace182006644c8ea595ba999392ea2dc346ec01e97034677ba8ce6509793d3c0f30daa003b5f49ba0d6448d17e056522e5c1b5a3772bab7915deb498d5dbddded5f86000c48e8725f5d6292261ec6e4ce6f592f00e1034a65ecc8dd16cd8f85bb462d0009012fde946a527b9f04863baad9fa5821168cb8f2ae3bcfbc619b2dbbac2ec00cc757fa9c1856600d19940ff9ffd3684d695419036324ca6492c202fdceefd00938e609408130b0b907ff29a920505fe4abb4d97a1988ec92ae15af976aca700e1df8aaaecd7e6a79f30e1e4027e0e9bb2d3d7f220bf1be466bddd4a5225c800f58511190340ddac2142dcf41d3243354310f05c0de0980444549721f22c700054fed6169ef68c22d07ccbbabe972f0d4c59545856ba4750b3ea4819b90ce4003c442e77d9395c0f1832be33a77ca42d82944195b3bf0174acd982750ac0da00ccb1805184d1636169ea698d36b7b72980a1a63e23092c5c324c93734efed100dcea76617d8c3f6a6d074f7b4681f4a10ef4948ff9cafa630c95f3077b2e0a00962502a16d3add80ae8157905ef4cbbe41359a29f043dd854d84914cf303e400a230343dc3f74c49b219b9d4ed085db62798fe3b9aa7d2a67ce0c06323687000042543a1326010f02ac8293eb803c5e256371caec319fedef126c8c21977ab00e94c7f11da52111082c1300ce85320d03678e6e98abdd0a7ab0821b73dd5970081bf297008440dedb9a9a0f898f589f3e2bb17848c575270ce85c75c731b2200b1a318e782c61fb08e4545f57fcb181836143640d70b567c62908d96c01ea900c1027bad2ef706a0fe60779f8ec597e52374fb53792eacc31f0da3334f069f00d0a5a86da35e6654d4842a4f01c8ec553b3d370ebd98db4364f6165a2f5b3d001229221b4ccde04208b73b818712b1ffd93c8445577fbd79514a123990ec3300ac56e75f3008b9dd71c3e69513ab1fcb3c01a14140c61fccb3d51ede0b46bc00241c9f0991d87db8764f9135dbb50e2742f3bd9eeeb16f4af4d6e30b99a14d00cdcc288bc9f8a8dd2bae2575954a2a2394a2480ced2144bbdf302daaebee05004aa9fb8fff82be4ff359b8a595cf0affc90300d979a1d96170a1ccd2f0cfb2000f3923bf688d6d2ddf6317d9b2f3e68ef35724252b7efbedfdd4586264ed91007b42d9f398471913f43408225f9b15a2512c49d4c8ef4bb50943dfc8726e0400b48a711d4d709ae91d951fff63c93dafa544d2bd1afb07a820e6ecb309572c00e229de36dec4c6e8bafc256f145757d0a4d915fc15e4ea8d19b46e069c05ab0036714073068a7f1138231e7d570bd1729eda9df6bec471785b9bea48ceacee008e0ff30dc7ed0505f45ced29bfce96637d641f6e25cb1abf2e2acfcc41cddf003ee8fe15d69d82de61c0b67328295d37a645037e1cdf4c6656f9278c1bdb4d00ea68aa1eb2c1013d068d641c4b310bfd4ead9dfb7c2cc37c7876631f4b2700008af65173c8e4d04ea7334580e45f4f7b107991965c37753a488881e6f8688f00ef2a8790e36f24ef7ba238cdb669cd3702235b2b33ceb9191b6170500700c6004697eeebd71294e45c855d842de3d3d19c47bf22920c8be7db66d19aa4b82e00902a829e015a384dfb903dcddce6150a5f406b4ba7d3583cf9dc57f32218b800714a83bb9260e976020ac6841aff9bb8f773a925095644347d370fee639dfd008341bd4d1ddb3dae003eb8f558deb5524767a51680431611056fe57ee2a9bd0037dfb476e929024e0a1213881bed894aa6a53a0fd2a08b372044fd89c439760089deb0261481e1b37b110c3033021d9b8e16cee9e8b79e48d714c5422240fe00a20e18ca8a4cd3dc9f04a74ad91256288cac485b3511db486a5a508e6ce04800b3eeae188a438b6f0397e4d1c2295a7e3cab3b5c0ec207c010e21ab43f89d8002ea20f81954f9e8b2e88f4db2a8826eb8bfb485ee72e37f5829a8a1d50563800fe541a5680a0fef03a79a6fba835dea98b166172848a2f4db933135374f61d001ca54f51d21ac6c6a4070a5ac9accacd2517d4decca895fc0f57a4228f4c9f009f368895f79734b9fadb679d4412f6399ce80e033e74f8d8f0355f229b67a500c5bc3a5add3a3b2d14cc0359472ac68181b8583ba91d575ab21010f79aa9420052035c27adbdbed75cf2575a50d83bc90d559d7f65e2edb23e8b4620dd00fd0074fb57328dbc16c70a39a905d1911ea3984652d0e84e7ad7f740a17d4154e700d1adea2c35570a7ca8e3824f3b0e05df637ca823a4daac7a1a55e1152975f5000618d20854b184cb6b1ad322b206f9d3b97f45031b1fcadcf0e381c026518900864e154eb70cf598fd9e643f5c2c04bc2a3254bf82fcb701eba4587744e81d005ee737fa6a615ec3ada5d76e05392b7b0d41ccaf1a100b65e6768f78520e21000668b387e90fd2844431249b9b228c0ac6f6947d253bd1cac2664d0022435800c6ab5acad7630126c59652bf2bce61fd278d8880dd6249c9d58d17615e5b72000182143231932069e805be87e144efeccea4f08180e870a46653c435396be100b3acf9fccec21f93aea9e76f47632a5572880877e9586f6c9c95dd1d786f0e00e878e2f399e7dcf9e04b2335e779974c69676c5d6ff64a0a1076a9c4d8b6570050962f88d389aea78b0893579b444216dbdf92bde40a6022838c707f3da5a7002d572af871d60755b76cdebb949a982b7ac115b5ded5d6866b2eb50485d8cc00c97edefac92c289fbe609b883665ef7c37cf14d31af49bbd99c9a3f868d1770053a1453fdc86e5a57cc59923606d6a9dbee8861673b7339cec5dbbb470fb41004a2e0350c5fc838b0d51745bdd861e9ea5bd694c48a820bfc9d523233bb1ed00c1d693590a350efe5d1e3e357347b1e23083fcf11e35eb502563cf4e1b8441004d4dc142ffcfa8bab708db63ea6ead859c646d736df85a85d459eaf9b2921a00711533712cb54f19603be6c01f209fd9a7186a7b823d9c1f568a5bfcdbfd9f00ae696fc4c185bdb1e66ba794ae9ec92f6e4535f3af0a7a22a49cca14aca7bc009a71546c796a33b1c47233f417f4984c42717007dcbad416f9e4f81f41fd30007d73a6df0347b73de656a537c604b6fa200fa99e6c5d4278e3ab843e9bf33100f659f97c3bfec3ba954779e77f9e1471c285a5af6825b1e880fa35a89a0872003eb7dff85d660b536f206ce8b6b80a0d6cadcfe782f2264112d51852665c4d00cbc2dc5b9c35a62c18264c6d2d135f987e5284aab291f824ba3d54526981660067fdef3ce8af52c43a699f3eed73883df25ddeb82257bf775f044deecb9f1f0059d11af8ba4a55403b50a78435ac70f0bcf691037b43af0bfacb2e8aad44df00e32d5ed979579393bfa45ea535dec1280ddca061e9f2430739c838290e65ed001747c6ba20f7eb820e533962f70cd9ce6e950c3cf7312fb573a1c0edecd9d4002bab4ce767a08745dd90595e99e33706a54fa7df57c2c78bf51edf7574c9b8003ab16ed1817a22d1cf69612dc9b36cc4c00647932e2f1d7a799458444cf52700b6fdcb679101f31bdf58dd2ff2c7bc3c99f0a667d1e0b5df8a489272a3bd0800c99493c2344ebae8a3d0a63d7e2bea1699073b8cb25cd842281d3aee819f7f00c9840dc90461b6c4392b6033c2efec44968c0c516707ed30df09c9acf619af000b52f427d1913ddf26f1032e92856f64a66cfb8406eaa87b6f427b8e7ee1e8006a74be167cc0b70140640a510deb3358f137d2f51058a0f74aff60fe908e990006beef434d88bb252c1e77f3adcf4e7da365be08248da3e03b55655b5580b40079a1ca5f88a277c1341d769e7ce0cb12b33693e23c8e6b19656c2971e337eb00eede0cb046e9c6f4204adefa25df793e964745ad8f19ae2a99e81404595de900baf3fc427ba83ba4b03b3018c892af9e25e1ceaf767bf655f0dc0484f82da10076ff8abbbcc78ee07a7eee0aa9f66955c4e360cf287abfc2233086468c82f4007f8b4554a6656a7640d89b4a2cd0bea32b76f32b17685dd56da76cef3f53d90051443354ac5465d8ff25cadf7c49ac8ffade622ace2566e7cc975a67d397a2008e10a04d5309863cda1bec4e8ccdf5acf4a2b506a10b852dbbd69df83ac75d00367a57bfcaf01cf9e087bbee19b1fe625343d42d6cf139bad834591e8ebf910005593693b30fbeb28f1e5ae099c5367d2fa07676821b0e98ffc207e8bc044100f98011a47b44e156ba0c5f510e08049d7c8b9dab0c00e85b06fb1005951aec00441e9460d62526a388933f0e3170c06dd8ceb296629748209b8a8f9c51edf100c88bfa9a97d27c48aa1a234904eacd51856ca4a39c3b8c3f6189ad40d9c49b00add8fa53ef0a98a62d736bb313f8e9c67f6567805f1648a1b919493011a2df00f53680eea026624b4ea9d252a3d6451894b8770e5786def8ae848249de2dfe009dfe707648b1b81638e9aae20bd55eebff5c55d27d6f9cb1fbec5667d8822e00c4cdf72e0a7af61ad10027474b92cd8f0a7b52889f7bc1c2ba2e38625a0494003825b186a59d0f0c4c6093fd4bc152d92841fbff45357e2bfaeee51712a3720053a2e7c34707d4e38850f664538b00097f35a2df23a483fd66863e0dffb2b500b2442564e2a2ebd966c46d3d44c1fa8bfb8b496344cc89c847cccda13d022b00297700e92c9f0ea0e3116b83f5f6aebc23228c729b72ce8ca282d5c3c7c35900e0eee9beb07b88fa67faddc9978674523817af1f9afbed5318192ec350c9d800f7f801672c34e193f76c086ae736137d8c81d63d1543101c94604d9f49a45c007ae3829720c2edb7a981e71642faaa4b037b2ff398318b1e85a636db55c27000fea67b17d13ca0f5d3e85bbf4a073fdd1f4e267a88dc3c6b7da97f968b3ac500a4e3fb02ca9ee48d94ed03f79df8aa76a4c2f5c95073b42c5319e006656a2a00b55127882886e8b0a87269d4fe70be00f41b63a546a7b8cf1bf224efe4df1500e2c4179298672f302ad79862bc902e80b31c983aa99c69b0eef18febdd9fcd00c42d3b0e1b43a0acf3a1c01bfc3c76df6b95d3e3b1ac8a08cda894fec0fad800fa2151578addfc2e6320f58dd177dfb5977beb20193359f5a6eb8a1be95462000544d9054f4ae2211191543a6aeade0c37457e7ae3ce5981b72041ceadd62d00e5e9235ba7b18abf8c195c764276ae94f56381ddaba5ad6e0efad4437c093400754596f19d50716aefc63cd8a64caa09606b61e361c9d4f390731be2a5a165004114f873b53fb3768a969eec229afc5b3b51ea56068b954a7c388ab32002c1002f1360246be48fc56fba988aa536e48aeed9b54c3445b029c1376de046f19b00664022e412a75c797ee5ba7102b3ff8b7fecabb5d56e339b51ea86e60bd19300820719154201f521b237f894637f8e9a48dca44e10716e906435130066ba82001f55046fbd17fa9ea49b09b63cc9ed23bd4c89f4616c5b27764b409dcb2a5500bd8734ba630c5f928c57934ca6e83334def7024f40bf6edbc25c757cd6adb20083e5f0c295ff9e19f58048b4179e6ecc9bbb12c589119e47016e52dee1a94700f94efc018797b4b708cf4093a343b380fd8b27760417ebe5cca2b062e2b8c9002d65abf0c5be8a86a8d7777a221910af1d93ddd7fc3156b677b7bc8e2531ad0080b456d4e65c1929bcd4ad597b0fda7e170c1481cf839dc17f463c3b0a8f7000212753deda27547dfba3e72b3c1dcee0a5d8e3d3940e10c2ebd91490da46d30049a2ce0f67cc230bd730aa553efc285362b68c995efa27db842de2c56814d200cd1362b3b2b35efc1fbee2a37e6db436f88e857189e0fc05f660266fd7e4a000b6ead8b2d878451d628804dd48f1701b48dee713d51618d8ad952355f61c15005b75e8f2425a6108116f0529eb612259db3b48d39c16f60c207af3b109f14f006a141b21b405cc32514716b700480c41f3a76902fd3b3e5e406d7991d660eb00f0850a47c39f30e781e742b8d20a37b345b6bfbbe2b8abeff8f4eabebd11d40079bcc2be9996e8985f86f9bf0108bea420cbaedc7ac9bd00946a1522510d7100508ce5c294b3462fce47e25d269896f115191ee133ec8a7a88f7e9100650c000a03f338d98d9cc166934bb14357c8d7519458cedbf012c125cf60123f1a09e00652ef87fd28d85191d6ddeb8261eda74a97f221a7692f3885d6972018a932300b891600dcbf3a18a7fee90f1d2a230bbb1a1388f436319f761ceff2cc5d5cc0031e3d4b1d044a348a81fa4c20bfa8cc4ba9c3d4c93db0eee61b3ef7bd71158000dc69d53a5796d18004c570d7aae6a195b11f452995676a2b27e764b1529c400d470ffc4b6f3bf3be07fe5a5bd0673e71166335c39028f594319e1831169f700d8ae9727e9f8954aba2f0ca678fd20ca5078755ff446b229a459e8f23c8b7e0032e49389ef7a18f994d3d4216bc28e1a35cda4297236378bafe7dbb871ad39007022711ba038a8f71367ece46d059bcffcb87f90addbce6e4fb2433816e30c0079bb297fd82a107233bd34222921ca0a466308b78c5560866d89bffc73cc4700e6e1280610cec7979cec678094110498425dd3da8b7c9b84f6bc9ae6bd096500af8248a9472c8571231aa1633070db1846dfd5bd773c86d2ee9631436028210023d6680796a4f440718ac113532391ab6abdfe686e2a7d75f7d9f6c7f147e900711e83bd9722d45d72858e0bbe8244cd5f293abb86165c260c470f1754170e009effaa15c758b34e7562289296094cb9ad33312122f245055555ac9334e7b200eb402f05a2418950291ea6cfb45c297dbbe818cad5478dbff731e4c70cdbb100551f51514e0c1c3093e2923e5313e43be536ddb386d3bc3a3744e39ead8cf400944e8753ca67d3dfb9ae9c23aa1f1004fb47f61efb0159cb6e76b19a8551ef005ba7beb7ac1399e721960c17119827bf63b340741512b76a742542ad675ff200a4047c777d03ef953483bf935b6d3ae17e5794901eb1207f46609ee8ec640a004da1b46d074a71ec5194c57dccb820d89b3727ac88ff7495fc1664509356c600636775d5b4f39b13fa98d84736a5ad5aeef3b62de08e83fe7f8085f3b5bb77009838db2acf9ff47bcbe63ae0a916564bee6beb51381c21bea4fb047944736e009b643d797bbdd562f1af4b85e9d6c13f37470ccfc355b5e36c8fee699e4f520034d140c934c8eca1528fd840bd8e16e1cb60d81e418a299e5de58d9e1494c300608a013b0562d41440475411e92c692c2b1b8caa0ab9632404f085254e712c00f688a23bb2290e5752325ad6d4ccd1ca23f384d28c493c304143d14464b49b0035c0e9d11defadd041b52c0aae0a60a0b81067a8dc1a032d39518f8bc4bffd001ddcca513539b615181bff8542e5c7f9ab47855065de88df9a9db4b136446500589b3ea1b89ad4c6dc21a6341ecfb5438ad060a88cb76dabb42e17f37b0e5900715395548654419df59f82004d68d42ed0b97e3838048f2caa0b674140c11d0052536c0a71cbe4dfb81156bd5ef2defa16c43fb425c22c563fe7a8003af24300402c67b67434c6c28b6d660e14e41ebcea10271cea5970263d3bd069a94a5100d28542b3dead8c66e007a4f2476aa66012f960a2c246516bed3989edd0b3aa0076ad27428fdd9d17ab49157c820c20f42c7ea74dd351cc35ca258d42ea6b3e00163292b6d60a9639e99053433b139aaba9196e2358378df96bf85a2e942c8500f10d102cc2e562794bab0308157c2fd66358b80dc096ab6b4111b030dc730100e07d96b0730e65e88afb4541a63787e602ea8af63803757c3fadd3fcf3008600f6a37221c222016ca4caea7fbdfa2f5ab844bf3e2a3a84d729bb851e4cbb8300ee8605edf018bb7842ba63514ab440f298da06bfb32447404602535322db6500b90fca233cbf2ed2665df9068d96d743d2894fb8cc73c4f76b0168a36da7b60009e485f34c725d5d143ca9a828f13bce7996273a6daa15d1439fdb9adacb18006f87e69e29d2dab17a4efd0321a7158b383f652f095d741f5abf98642174a200ac2b4d6bc14e3407ecb73d2639eca6a67bdfdec867b71b586aa7023f558dce0074dab43aa6cdc975506ec7b7f27b48e0050854b9bad280e8635caec1ad25a800978797d823c8cd591ed44579227b6c305e1cb8d28654b4bdac4c4284a5d04f0011c92ca873b8dbc1b3f5430ea953226f02404354e0d9f01bab291b2225ebcd007e1a0cb2b6d321cde3cbce3db1e732f7c12f819d8bab52ed921c68d71230e20092efc3b168db7fddb48794abe1b31c1da3e6f48b81d10e3544a57b94104083008602377989a11d56474a1173b859e536788b9897c23c18fd6b933c48597fa40076c26808df22f1702c6c36b715ed4cefac76dc0efaaef269215bd57eb9af8f00bb85731141107fae7fe7af3c6ed2fd256cd4bf52b145f69f8b618bfdeb87c1006316228dbb3a09a49fa83c8e0a3cc55422ca82cf440631f35aa83b983d25c6009f6360283fca1a0a2e488ce48ea16b44c7b40201fc5063c9359ba11c47537a0016eb61753fa6350d9f55afc1f58f0b246923a489300b20aa7a447101f8aae100b9942c7e8261c68c17a6c2a9541201796f31b0f3f863e6c02e1c69c0ad5b7700e5eb79da1bee81e08dee0cf603182c996867e97b1a205cd162f19c662ec405001969440093fd990d75ef7cfda3b632add6deaaad0d090efa8889d9ddec11ce00f46ef8394eef1d6450ec1b0fc0b258ee8f0e1a4fde27449fd55fa3db60a36c00d9055f4ffc8c423eadedc327d0edfbba0ea041f8d68d868d7a0b13be1905de00eb5e2ae3230e49ad5cd1caa33d1f771a583269a435ea45b6de9bf38309c06600c73fb3cf216bb7e3c5f8ff5f071de7f7ddfb395602a2c97b988d3d96d0b9d300bd22a90eb0bd788753153bc9ffe3a09f50500897d1aeb4319a1ecf86e5ff1e005f7057c2841ab2b1845317a7189e596a44538ffeeb37220819e937ede2815300513bb921ac9e982f084cffec4f45f7111ee40496bb72b67966dce7974a9509007a16c89f54b874c3e957e71d51947149456a867efd7df4f6fc468f86d4b5eb004e4a24e869d68097d8ca94b871c703b673d698e4445dc644dac7ce7ae887bb00a87c86fa1e0ef30855e6926ed0fc7f3c9d6d9e10b11aab2be731311c846c1800e2c537157ccc017cc714bc72286ee3e783e244a3f31044dbf2167c272f8d5c006b8173c3f528742155f684731babeda1c8662fbe99949272d2ecbc5df06416003421c9d5127854918f6780feab0b307b18271c355d5397110a83000a01facc001b30462052f6ffc0346acb8be1ec7bb8ecb6b451025d6d65d738d04b7aeda400419e2539581aaa283a6f2e7f86903b1ec802853849dbf56ebaedde38fd2cf200885e081405beaad9b1073d647de8c26bda05ead968dc20503442527a60735b006bf2f781e6caeb17ed7f5915ff8f1f6c58093096f74538b9de86bb43d8d69d002c9581906d44ad845efb610423c6bd654124e0766757367321d642d9aa807800dce8e7e77e46414ad3ad64cc5fbcb7319f2d8b770b306cb45eb2925586ec890031aeb01c51d01c20c81e0a10dba2ddc4b69e31299ac02c86e70f0027e40e6900c1701dcedb4706cb948c73a94623fb707d58053492712c1b5fa1b4fbc36500001793b2232cf3050eedeb43d977868bcf5933bd19de31fea79725ce22b323b600eb5768ed4c8c033b34c95105c2a51d03bc07824adb1d9c870b4a25db7b299d00ff2f59cdffddbcf15a2637f2c0bf959e1eecd8d9c9c1d985d4560e72c22b0600eed1ea8a81a6aa475a2e3b987769224a1214c750a580728044eab092c4ee6200ad4d8d68b9fd27bd8c7fcbdc3d8e9ee0ff7e89bceab1df75acffdf13a4d6080018422667e0e74355ef331f3a562851d12657283a919bae2e1845d49416df7a001dc8e1a9e530e4018333cf574df6215f00420429b4d09dbc9d4a2d341b78c700be920ef32374f9ef21cd0d997360fec277384c42814d8ea97fd8e8cb21b96600f0c5f510116c3364189c73ab7a95eea1621867908996ba0509d8b67381f6ce0078ff2802a39c787388e4a6f2a28fe51e7258557f8994ed9dfcb5d8148d5e2800a3c412db2d349681d5d13bbed1ca182d778cd0d707cb49f0659b6d9c9a2b9b00fd9cd12072f5be511ed5eb8fb983b73f0382d4c22cb199ae3871f76074422a006008a0259043631a62926adeaf2bf3b0c6de61717d263659e676cfcba60ca700f763e30b127291d62cad328b53d79e4cc136c79733d03fadf160e133b0316500b42ab275f73f43e0d561fc0095d39e8cb099ad5ba006e6d01a9fd21c1895a400ae544787768a5760e51805346cb0e93361ddd9d7e74e989ba64bb73039b33b00f9850c071662059f993a451e42ac4f9f49eefd5e903c85a0668a73b43bd5ab007bbfbb7a41a2db0e6c09b3513c462235b6b10236df67b2aef6d3b83d74aad400e66c0a457c24f7d0a7221ff681abcc1e3428d45babd3dbaefec99ee726491e0094cb30c62a392351fe1bcf41295f6ee65cef16105a1ac0e6f74e095a107c0100bb7ceaa6eae07251e13ac9f79bd2037b7b0545dfbfd34dfe2fc33a79642bab00bd6dbb2b0ed6963aada906b0c66af2aafedd93f1553cb4d297499c190b3e6800aaee8d5cffc54678054bd9e285f584cb136a5153bff69f246cba07ce34d5ab005a39bf059f378263825d2fa5ba5509217af96a6079140e82abbcc21f16b5bd00c095b5cb518aece91e68a5dd21db43fcde54f70f29ca15590cbf15b8b8828b00ca9fc27ea0988edeb82144eabce5f5301ac0056bf55d35aac7001e6d1df13e005d91e1b010dfa7cf024f8241eca41c1388f7bbacc585e0271479158e8029110036cca3adca3c9e5948f8914109ab1c499929cd2212f2437b8b7f6dbd789b3f00844b8039a5c95ab625cb35ccdaf3e656cc7c672343ae16c53cc8127833b76c0012dcc188644ce2c3c20b063d55a01e816a7b8c5694f49e44d4aeba3c7469e0009ee9e2078c5426e93d14cae9415ab23c431fe303f0d1831bb5ac0f60246802003d780fb066cb0f30e7e46e8f4722e1b6811df389d761674f2d657a56d6e16800f3b156505c0f38e72b52d8cfa078b95ef1ba71108a7a37f4cdc4d6974165820029b7edbbfc7695fc1b6e2ad1c616be239db331621496bd24cdee9c27c0fc9700d2ea349d6b134701cafefcaf1df80d1a30b7fb179a3aedb2957de67e603dec00237fd9c9194c808d58ac4f278f4c8d2722557a31b110138e61232bfcbfdc58001fc6137db54212aceb6805d549b6e4c03a859a9d9db41c24013b7b7160f142007ab2a656eb07c3f5e903ad0ad014e7c43227bad42ed93b96199c901157b2e400d32fa979d87202049d6d70c672e784ac0246872afda31a49304453b7bb526f005e8c2bb58d9bf9679e1ed1c81f352b4fab355b1b64975043b4f7d050bccd5f0053c52fbc431ee830afc8ee8fa2d2e11598b82cc507a24d34269ededc1c17af0022c9aa64fa6fa87a2da54c7b476e2e580678be6e31763a7a72433c82577fc700de095c9c002463e04c907f0e9032e7171bf8abe5b1ef4c230f49b013efcdf100b7d07e20b168fd39fe088902b2baf3925f618a17b15fbf6c76e1f02c26087700ccfe3a6a35209bffc04e50d163b65d62937c80e79ed36d045fdceb12514811005a37d836e4e1a307158c26951ea927acea05330174903e44b374e6a1990bf2005122df82c111cc62d4cb4723607678d78418fb84eb8acd4d389484fa6543ed0067c29ae6b2278c7e9b714b9a8c64d9545e99174612debf9fa7d00f2ccb7d5d00bb1c6c22b50c9631d8dbb0c480c17d13b81ec6e942fab4e9f3ccb6898ce32a00266473877c286053b13cb43c17d8728020843f02874b01dfcd6b7c1e55d78f00a8b3901cdb774e23ccc0e83f620b835c5bac98d38ebffc55584e5b593eade8005c42168f376f51e7836076d9c75a98f7ab533defbefba2754365423219e5aa00f762aa5b4fabc92b6caf0691255c0e8875b9c3b1489383382920eabb3a43ca00516c52524569a6b92eabc2f5f37d56389d7152092102f3285c612ddee3e65200f0ed2ee0ff84339f67a75f9f75597fe19aff0bab067db687295c24ab43b72e0062ddc0ed39a85285b8c5cbe154bc776164d6646c519c02194426cc40338a140087869a33f9cb4a5954dde732884cb79e6de0029f2f49cf4a2a19aa8df9b6d600c0a12119a387313eb71c735c13adac1aff0fcdb135c2d520b34f552a55ce7200665bd18a8bda23199a236e187727a9b8237982fe7561f12e2d4fa440dda66300bfb79b83d6e8542f3cf6856ab1dea8299855642ad4712239c2ca7faa87542e0046a3d2863f427e317fe9d17300c0c338a36ff4f85c401659c7cdc74ff4c20400256c1f6d751059d2212bb3e6b0fe1950a34263e1436934024d77f294feb88a00c5a394e8a2ec013cba82aa55725b21cc027bd84d6b38c29df32d8b6f03c932001dbfb5ed26a6874028a450cd2e16546ee0f35618078d31feaeebf0caf22a8e0025c98b00b89e18b70218e6b5b64db048364fb4e1232dedc17929e7655bdb96009882090b65dfff8f3186d13925faf1859de204c6d5534ce9439ec86bc5ccc100695b249ba165d36244f6c11ab2c2fd0012315f320c1a16651515655b4c78f80086fa51bc7833ebec492c3fe04bf6b32ab4c1aee16dd16a1b9f93db80a4120000c1ef998fe9a3fc69055f186e4b71d8c82d580a22841a2064e29a541491bbf500d111dd5ad4b890dc146c0dfa02ac038946ec852aa13f08a8485a5d7a69183a00583797fa3803ecb6b40fc521ace11b067913a2957f0b6ae8b5a8d419d94e1c00a8d90e419f17593c0ba83baaef28f95c6e381e1f6ea8f4b0631a5d171da53700e10d6f9e738e5769a9a010dd53dda18d7dd2b398bf79cb05ed584de58ce5ce00ad3f83a307b0863f001883277ea45fe5352ede4be383eeab7608f19da275bf0042279829e88f0cbafdfd26828779eefca50d418ef1891d88997af57bc5081100dbc3f465163c85923327ebf4af8aeba8b8b053858f18d14caa2640d8957230007db763ff866c15a0596fa608cb88c3f010a9f432dfb4854b7ca9d4dcbedc8d00ffc623eacd1112d01e7ae5dc3f9676e0e56d5cfbe297302631fdbbf499140000cb5fa52f5c817c765ff74dc4f38419a57630ddfb6aae4c8ae64dd4df950e12003c0ac4bac565d544501d725b3678e8e07d9c13864d8f942201e2aeea23184700d7518100a47edacbb3709347f66b40f4d11fa906b326dda4ebbbf3550d64d700e8f0ef5f8c610cfaccf28a7984dfaf6d55070d00f87df51bdf52363681073e009f4eaab09cc68cf3bac570e8903ccdb0bc669b2e7f58fabbec118ffa82057500b9af549671fed1504cf8717f28e789264cd1c05ec2b1fbe09ba235484883d8004e93217d18f085137b5f394893d95da9467a0c5130aaa9e71f20a40955679b0061f4419912e63a97331b2c7f9f815c796d504d0e8a51956cd882e4daa3ec9700e4d85f272bbfdae0c3ca1848cb737fc0e29a3310f08e683fc1fc060a61b2b500e4c29803b0b3e0101c6710227093f18ffccb6121616e0e8b99b93df9b3191c0070a1a273c32445c3c37933889e821250f3769da8085479f892e6b1b9af474100f48726e2d8afa43487c8603bff9c125e0ef293cc891072babf7c3e0603edf2004b0738af32bc1a300c2471b08e899959de70b7911c5743c08204545189ae7500139ad755bd940a0fc9fdcfd80ddc1d206da2ea78babf64ed1298dff68cea2c00fa0227ca5797f472967b7c446dc2b3ba0c0ee9b446ef2a93368d9b53fee68b00cbc6a81397071f0f4d9b4f88f85c28e091caca704ac0dc3e494b9743b3495000bebde3a8a374c1dc2e37e7acc9f10793539a31e805a47d87d5e55fb4edfce30025aa9c19d1c6f8f074e9007d39b110e301a2815486cf2ed472c54e1fed847300e049799b82f05574bc0691532774a98671fc5c64f9b0ba0b85450020594b3800ac13d8e66b4e9fdd3d56bdbb7b493a5513c5ab7517f7c6478b7969d3dc811f009053afeeb967618d5a8b357c15cb2e372955af220abbd5c848330224a5d5460040bebb840b2ed84b578c5665afe4e8e38bddece3c1c2ef293ab17feaf90cad00f0bef6c5013f0a87a0d5ff774a59b33d05d85667716050a7949bd7901716f800f7a45e1bdb22fa9d8816fa514f4bdaa51e48fba1fd3bfff6a6f0e92fe7291200c78807e5d3f73a102f43df1847bdb3f6200e7215305208c41684b438bae96900a2d6925c9c823e522f1d7e0030689e15558aaf1a11bf5e0371b9a3423c887f0049bbc6850236990453bfd4194d5eacedcaf77af6abd2b436f7ceffe42f72a500dd6cd23db29b47e92c961eb0b1958c1a4b7c2aeb1e53791ea9a8c7377edb9b002c146f9276ba2ce2d1cd5c84b332f5fa3c2c29c6b473464d913f6789904eb70000b32e0f82b75a2001bbf50eabdbad05dba46240e065c099dd686c97369fae00bb0b5caf35205057a1d14a9208b4f5aeb9b923463e5cbd307566a589f82c1300a574b1a6ec7465525b6bb4ef06592cf422557cdd25a120432043652f026c58004fff96269f3fe269c8c07d27e4a8b9abe38946c7449052bd8370422a2e99b600b68628bb5f9935e95e1f4ab88715215b30dbb96447fef74665097163cd4ac6003bc8617db9db513b1332fd7e73e76fa82c03c60f42b52521bf7d2192bbb794002657b9879fdba1cf631f671ad0a2947ef6bc43ce17bc0bd1b6702fc4bbd0eb003f9e03ad75ce93348719c602dcc128499555d3c2bc9daf52a321a88dca226e00bd3af63896b3c1a821a62d2b6b6a4858de0db7d98fa14eb3aab9f8655db1b300e0d7ffc9b73b40598e12d97ef5948fcf00d571324881cd4973e61579167754008ca14205e921846c238d226bd6b3fa71c88e2684849f9fd094d3f26960d1250041ebd0eddf720ab0bbd40285fbe0d3177c65eed3400afe1853d9d8c53d749b00426713abe51b40d1702514bdd48520a43a1ab7c2076279a8cfb9136c2133470059b0f473e5b61f76251005853cc88185c41f1f003c255ce83d82938b64edee001eb9abd77af3dcec6f026d120ea912219ccd086c9bbe7b1c107530e71009bc003559df71020989b0f335ecef26e9ffddff265d55bbd3185d281e1b74db041c007a9059e2ef05873cf2b2d13a1e288982e8b960b6dc3bfb1e30f0ef3fc848bb008893fed201ba592cd1b929f616e188ea4458d70ef521fbd95e6e8d8328db9a00b97c2b11e9b56ce13f598026e176d7b260f96246f2496469475b0472c33c9800a5cd9ad2a79fcfe85a2ecab6399cef714e5a07b2bd1b6d8423f169316f30b300e4ee605f7b550dc8a103edbcd21b563f67965a687f517914b12181920e4d0300667dede0a9284ab60b97fbd250f4d42dedd4f1aa633d33a00b30f0039039d900918048fd7943a48632f392d89987a928f9fae27270e669d4a6a3fba3b51e0100083e4dae65e60343730580d3aaf639aee68a9c0d6865e75303fdd903b820ee00aa82fbd8503022a50ab4e7adc5cadb72fa7fe336c09e27b80a1308f7f035cb00f081095bd53bf25bfe06a3547a408e7007e74b83fbd3638a340619abfe48a300cda808c8b5b60ccb3346b33114f375877b1127c782358126e03d460c6ec3f90037599f33497267b0390e78f7b70c1c4cbec04780adbed1577445f96ec2bbe50032539cfa2fd3edbcb92199ab4abb3fdb144bb75f4256248adc83f676cd81f6001979ad298c06c7ce2cbd466110c3bffed6122db7a7e0302762653f1425a1770008ea072fe3a92faf954ea2d46713d935528825473b09a2b7002117745815c1006f8fe7d446d8d20e194738fe7f815448fc65e806e9006436891980fbcb80a500f282f85b151d7d5e8a5b6bb27c79d3429e56919bdb7482cd4b87e0b5c396ff00d21a4bb60db0b2a7c80260bdf5a29960e0c214e9ca3174c1c3475aabbc835300e12cdb055e327e04b23d335a61cbe7901aa420f1bb1aaaa78ae49bae0496fe002ecfa52f42611a8b440f0e3fe92876e730fbf3e0bf2c33bc1b3eaac20a5b5d002319f0d7b94260eee66a148f5102e25c8037a4d28df4514a5330b6d916069f0026c98ceee20bb52214b7aeff0cc199be4129d22478b022fcf3c3378cb1e07a00a05bf2e0b14c9289a912d1d42d4c880c0ab45d587c59d185585d4d8fe7e1570034d7101b4321a5d680ad8014fb2762c202378835571424c2a85343398c70210039fd5805b8651a39fc8aeb993258cf940fc7936478ceca2ea8dbed628a922a006b91c2e220608e40579786461aece154447a219a0afc6a0f2fa3b5f74fd24a003875f13b8cffe8e4684323c86a4820e7c1b820fbcdfa1f5e4f5a50ab8ad4f30015091383364e379aaf3968fab60a85f80626b1954c872c34c87842a91da861003ed30245fa845880eb217016bace34660a977d11c124d0f6eee50350553a1c00d569d98c67dc2b4ec6afe577c2b970d1092c65c721b258622e69a623365582007ddafdd9a35280ef7ebf54aa3b138fd2cdd39d5be8d63547e52905ac98fdcc0040e4971a0511199a543e756d053dad063bf90054b28ce202930ef1db91095300f50da75cc46dceb7cf75a09bb4eab2632b5bca5a5302ffe22e6c33e168ccab000683d06a24b24e79d15164f2e18a40ff050947cce7abcd053e3e368be70fee004873befb8696df9403cc513402d28814da8b9095db2846c0e6b124814f392200bfa7479ae9788f0d49c8ff5134bbd1617c3eed295264337290fc9c750e610a0099adc60aa032d31ed7d6e2b0280f9603344635297e34629a8781e085072c3100e29ba18d53994b118d706473cdf522d27f574487df2075c750e1aca5c6efcb00541b94176ebd7f00ddf6d6f06d05c3d673c75514c5ed6c5851f5bd5c028db100234e77deaab208af207d5f734f556cf0a28ef24a7edef0a5df463fed36799e00879044771c3260601e56c4ef47989d55c9ceb5a207eab1b2922c6442b9be0600c11ce46db9ed52fff5f5d3fdd93aa1f6ecd6574ed91747f98fc4a0ba22f27d00949765af0b8bbf4665307c409f04744e05734c7f0766a17578f94b828109730020ccb4c147a737cf23408e598a2cfb44092a803aefebc4f9441e3260bfb25100aa3b8768d2e48d4042747b9454b35725645b78e48143c5d80a93f2815b20ee00c4eafa6b1ff7827a52c541ab5435daab763b0eb47eea2ca16caccd4198d0ab000057530cf078a3b6cf4b2f19ba82b25dfedcacb4d0dac685c73b42841f241a00758d97bcf8043ade451a394ccc89b491cfce4ebc4b5987ed7310395f798f9e001c23f15bf38898548ba2f5f9657e7e94b373f16cb3930ce8f137628bcaee9900d80bb48a9d1486f9a2b7f5a60ca89c55ca0727c22f9bf3e09a1cc1a7458f5300f2d5032bbf5f439ed30629c6acc8e3d19da8efd52599e37b2f8b776dd360b600633a3682573e90602a5af7ab124ef0d7d1b456865d4851fcab37234c7ac99e00a12819e40db233508a200efc47275225afca5ac53d683ebae0ad7da89bcee90062acbb45061247f83152ca0c291ee4989e3ab9d4a1369ec4a1c895f0d840b300d9ebb4546f63f76cb76a303c9e825d2d9262e1e76d62719978e8d0a538e92300dfb8ebdfc414f7f90d80ecb3c1c8f86ef77fc43fc4447a663a8898c0c994d300d74a55e62263aab6b910d2072d87eabd9a5f88e93dd6ed848310298594daf800a3901a9af7aa9ea3d74a4b6cf74c6ee2e3a613ef0c7fb2e110b18000ece18f00b035c49408f700d605f52d063d18269bd5278d2e6c378c184b3b2e1ad61538001a473751863be97f90ff9036565deeedaf88e93849908d22c8cc33408460120076bf48b06c1d56afe9fd4a8f01f6738d68c695b64727b64cf22cddea72f51c00c8e46e22b9f8d7a4bf1040cd93a528f80046df3dadb5a5742e13ec8fcb571200d3499d8a8bca921b8db7855edfa018bc1073ac0f9f7e54ad1c8e0ccea76b57006027a3106cf7a8317ed64b8b0551da9115189e4496201d01a95e32bd7ee2990056c9b2d8f06e730f4ed137cc476131eeec90b1e706d0c579f3c8f983b44d9100f48de35578a1a640e17d388bad434b6d4972eb3b466d722142ad27fa23086200035e11d1d6eba14d0f7f1a581b7f10a029e0308e4915938b39782de580492e00ba83321c60845cf486eb03c4d16b36f62c18144d4a036d1adbf6711e4a044500888070bf3a134eab6f4eed342563c8a6e4a5e399bd7f8e771998a6b8f6511800b66944a4983f06a2dfb6acab0325c6b8ce933d4300f6862f79ed48d44cc42d007bad7f53eb59d84326984ffd372d191ed24bb0e6fda43c1a409150478f4d7e0045a5a7574a0680fc12ebde2d6c18ea0f221e61469eeebb2d2bc8dc1ef4f44900d73f31bf085bbec952bbec8c4b5b48715452f866b9292a17e78086687b6dfe00aae829ccb5e98d946d90648c66c3101c38bb0f93f108c35321d9837fd7966200078f1fb575374d8bad24a753f9a8c7b40e11df8ee0edaf4765cec82121de9300026711fb74e7215e7a818ae9b956f17b43a3a7ab98a2124c8298571345801800ff3c604fa4070adfab11f22ff3d520096a87e67a59884243a4fafc2c48604d006452b3f997394e05c8d424ca431e8f92b298662b5b84fa36fb2e46d8557c0700476714a8839e89f254ce2b9581f120fe58db17700d8a9762eb5c491589d2e6002715c40f1850cd27de78063b163d7b1a5ea0f1576d1e6c7f26ed750c7c0a0900fe2d66cc59660ebdf6c9e1f0c93434952eb0d4aed7b6c1cd9f82490a269d3d0098d5608a5fb91f03e12fc15b9057d527ab56bc5ca32f66c75dcee1dd693d80002a0eae4e45d859f4a5d67a0afda88c656bfe4ab7c3bb22089d06d0b909e8250087f929ce52eef2bbe3e3f0fc24149c48367bf856b45a501d135965531bed7600ee6add214eb42a4cbdd72b0138fc213e48eaad5b470e4205f86a2e8ef0910600862983b50f32b2973ccbca22e0d253ca041e56a86afa07b3e62c173c4fb4e200ecad35f37b2b436197917a0108a8b76106ef4684ca5c6a3bb30e78b3695c2e007a28e5a6c2a64f7c9d0a99ea2c77008b867c45772b6e9d6f94010a8f898de9009c0f0f0b905d5ca5d39c69682e614ec2a633fad3695316acc50b1c949ab2e50028287b6067b85d2a146d1519f8b382f98141d021074aed353f2fa54f1e4eda002af33fb23d9554147431079be702b4bd04dcb7cd57dea68317b72de7dce55200919b5c998e86b5b20cae71ad1a8138d49972bdd4dc738a2aa8e9d06799a8fe005a3c32f0c9bcc078315dad2859ed7a6256ea98a596f3584a2da9f3e8f08d22008e44e248c65bc2e0a86e177e4d2bbe0d254c521c31c783fa8bf25a9075c98c002771b99b777d9079c0a4be4143d03afa3735b4ac32a04fe1a0b1d2cf6aaa540060f4425e3538f6f54918e2c4e9eb4bc2ffcb3ba60da395334df09c205d7c2a0084754690e40b93e4388cb4db710ec6a38e8e29ecb2d0b37db69779a2748a7b0080b3a85366128b91f9415fe169e6dc51ac924d60edec9705ffe4b41051ede900280007e139b4d216fb006a237201d60f71665f66dba2abedb2f908cc89eadc002d16aebac7cc45e8778a0fd85c6a07e3d8ff7104be6a730cb9c15b8c23b5a2003c8ad83c2a070053d5c4bdfaa649119d91fe97588e7c3310ba4bc7d4ba7a350043965ca7da30109eb325015a246df49ab1ad83446366388d3c3d44a1b27014002af51f67c372ae9798a3b02d76ee238a1dc9599e76cda44de1bcf4c8964c92006dd21ec66f875e56ceaf43b07b7cbe30d3b8779a7dd2af949d32dd9de63fb200227343ca76829fc73987a2a5a52496a781abea7c686f1a5280ce09d14d79f600e77bce4ed0d9b69483056a227527e2b5fa4f1450d15955b41498fe83acee6b00a3f09f52a8eb9868dd507eb4a65503d26f61b0c5b9f0552850acf69241f63e008c8d43e2604830d8066e6c25f68acc09e5437bec6a5d8b4976912271ab134200d2f7bbaa1b41c3454f2ae137caf6caf28a680f02a1fbd45f0ba1da7c480185000baa994a3240caf4b7fc3f5ca243373e32902140e8e0906b20c54481d7de3000bfc95bc0e72a29f4c9cef43acd7f4babd8cc5de8162621e172bd92aefdedf7004445683bfc5b9d847907b7442d77776b180e7fd90a984ea5f8d19a56d2d20d00eaf9aa43877c376554e22c202b5b13e5b01ff753475966e281da5deaa3144e00a4808c0c5c4e42c4907a7c631506a499ad94b9b0d10115cc1f54930085d6e700e56901e9916a9d7abed3a686c237b7520d512413e6ca4c173349b0770997670007969934760941cd30b87859300f84b5c08ea0bef49a1d7a98f7bfdaebd862001923cf7bdad045a9a1951117e91b8520f4e95935e21c10446bd42f19d1ab280082109118f0da06aa2919788e28b345837d9fab83f0ec229bdab7e3ef873ae200034151fe34a0f2181c7c4f3091680edc50962b4749e26c4a4c4fa1c448dfff00c7be0b3e77ef5b3420192f711224494cb2e2abefec2d282db38f1a5c46c8dd00ef972742e893cbcb8ddd0d489a1c40416c6e53e592073b9c0c98fa1a600d460053306924a2f2cf421822a46aaede8db116c4712633a6202b38b09d4222806800dcf43107e74c8becbf506093e56d3487eaaf16217fb0b3b16b67051cd44dd100c28dd3cc703e99cb016ccc7882efaca7f170e1a02f4f3c14012995fe8ccc7400e41f7a4b7e6089fa9ff219a33215609d668db202e69533b0e2ce9472bb650300987db09877abc5eea1d91f5f4def67137e3420f5f9f8d2ce37db80885e63ac005da4d98b2d58bed6ee1f6ec66585fe220ad5fc37e4fba7397e3c7149354bf600bf5c7220eede29e849f50c73a42fc4f43faf97cac1b0f93fc6e3109135e0dc0028f37a98b1871154d9a326428509ebcad4e28a6eb394b052862ed1dc265052009508de9dc5dc836cb6556bcc868d806a07c381cebf1f48932b70abffbb9db900544b5b5a5b7904fb6a40e798c7a4ebfcea20febe38f4fd3edcc8bca8ac45000028f83d43346b937072d5b15d6e24f506fb214d16ae8d5228aa20c99e7bc7fa008ff7912ad16dda451f91f55cdc781e8c314f3a947dc28fbc3a10d79110848400906b9aba142380817a639577561810832ccb4cf53936f7d3618df72e869235004a8e3122a95c311b8412395bf8c7f9beeb70a49f4a6226cf19ee4e31c8587400b9cd3f9f6551151d5e1bb8089e4e3bada8c92d9b8f109eb1be6f6e30cb237b00367a0e02b45db1580b250fd0cb3cc4c5bce7d8d5c9378b6bf8179dab9847610034793cc98f17cd7aa343052f297e6d1d902f45b1d8d0448cbac6360ded2c3600eb44f9bdccddf10cbc32aabb910baccc731677568d384172583cc7a41200dc00ea34dee172dbe767487f099691605390d99530ac8c5d295f2de9ace6c4f1ee00f95b8340b5e2c86930fb908eabe2676ad66c1b85420a13c93ca628e259eaef003931ff0c67a8351e1c7bdf49b80c7634e7106fd9e0e456fd4396fbff7dbc1300c902f3f65ccde219c5c962526fe0939fb01d0e2f96051a56852a11ad00c00c0028538ce109f8d254a9ebb8dc9247a062157dd20dfdbec6b63018afcb25837000be7f486c7b8c2be90c0ab297a30c4b9d1857ee28be1943641d0079c3226544000ea2381ce1b31bff0fdb348e9c133488918a1a8db5e23ff8264fb3677ec35d007ddcd36736b42c7e244fff9618bf8d0c6ab2cc04d08c198ae6632bd48d8bf10086f071ad705b5f02f0a1c40fbedd2d547046886ccd8b420601e3a8c592d40c0020eaa5c0f8d6ed05de99dba852deed9da4f195e1693acc0e6af2ddaaab2c64003bd3702907212640b2bbd332a04aa96ba5cd9bc08e9be0b44f290e0abccf60006f51dabfff5f2f0d495b353356fb8d360758f6d5fa4723282dea778dbcf8d800c2ce71cb22681e38fe00aceb938f0702f94ca3ad4d1ca0985b9cd534f59ed00029db68d3438a8f27cc3002cd386d803f078a9a530a97fbc3a9f16850264688003dea46b041bfb11149eb77ce6dcf0d51f38b25317e1bbfe3cb58fafcbf0fb100629f5adb4b7162cf17a59d848b17bf069e2573d2eb577a8ae93cf0617af64c00f6c5c1348105f828997e61de4cfdf5d854480762d7c4def811ff18cf0cc091009226ae4a0d34822f3ab1991b58c759f0e91c6ee4762401ee3f51a1bc9914d6002ad08057c361fb18c3196795d10e39e618eac769418541075caca92b396a72008d5b93ca58a690529f2bb2f93b9335a603b026a0d11be969b455f4f34204b700af1ea90837d36b37f167c9ac104e502b4af03fd6b4a74b23c4aa970c169c6b00266905fb3e3549e3c0efbc005317498c9a41269817fd4322178afd7282c1910035a6aeb04fb23df619e70df830e6a9924d8e9ddb2dc623b04826ee9b5094450068459e47e0d04b7b539a833220ad3f9c49997a33631bea98436fb9a12532a80078e788a59add53546c4e3a09eb8734c875e855611cf17f45db8aa5ce4f82ba00f308de1cf83d2d3b11a73b465ac7d0fa98c23827e9a9bf6f8dddc28df94b5b00792acb25d0f2dbf010f9496efa1e24bc260e14ca9ebe08a892d8215a9b401800b24372fb54330dd6c6725615f095eb879e65cf7c13821b63be27b0904eeb930097d29cbfee8943cf50450e0377ddffca71c01e06c77591128b90bf7ce0fcf00046b0434e30d84d4fc3a4d7e2724f63ff3aa4f3ff6c15ba9e526c4bebf1d87100434cd395fbdd34a5e7097475949168a96bc8d308f8203799fffcbbdf4b87860063f6c5900ed25594141dd0f5237c452b19eda62e63190bc71759fbff11200600cc868993a46ff56c8d180beb7ae3226ee5ae2593e06dce5795802661c5a15700615023a2d00aac7e18d9d89db5a7a7b1a9c12e1db770bf8063e569e0be7b3300b740991afaaec45680ff89844a8b91c98d6539b25b7c150ae773dede1e05b90031e9a9d1331cbcdd63d300aa59ac64e90199e74bcf81c9de2f00a76349e8ac00fecfd5b4be12d56307831685104ce448a8bf9ab75e1cdb3d7098d00a816932000b1eeb3329099f14aad4b766177e87ad47991880153706552d1c8b01cc4d9100e37e0c88bffb75dee15053f9f1b58c8329c61dea938a220db170059dfee778006c70495abeea038511756c3d3032edfc9da35892fadbafb857d549908298db00a733c16957711c2e01b3be280210ff2784cff59e20171347885ed0635dba230023f47651b1ffb4a3406376ef30514b0e4c603fb1388bee1d78870ea6e0e1840080a09899deb9a875cdd84c795a4667e15d4f8862c88f0b4e6788009d9b8f960000e5130758278f41ad68e32e17d6ce73938530d011850023dd82664f323c4400bb42ffb06e8791d0fc9975b154cf476621b327713c3605abf1f6de75c55e19006a32bc77ecf0a12a0daf843e5faa227b78887d46acf639866d8bbbfc409e5600ba8cce54e2a1cf510d53986d43d44091603d7c833337fafb2bed11f0beffa100368f527f1ab61825f69fe3d623c0043c1aea33eb8f3db5fcfa597eccd520af00a87a533cc4c3a2c2b28472a510e575a5521e13caee8ad05362f50aaefaee4a000d4e56d9b42d3f59834016f2b2aa312051f6d3be00f4dccd201776948a45510064948c19ff494fd4e1d34dd49c2a0550dbb194000bfa92c8666fd67c282814008deaba35807558c3d722e821cad8a1486739a1b78134dfaddcbcb29f0d005300ecd2683ba079586d698f24220285fa75b1d9c73413cc053493dd8a178a2ddb00eecfc96566332430b943ebc2f8a5ab388cc861f77d6ac2d5be46da6920d7d4008ce7275b4a6d53aef14c248b8487cf58916ad65d174533d7cdd2d1475c128a004e2e22e10d8976463c3628f0b5e4fcbab781135cf2a313d4a2b46b89d2dbb2004423deb3e1e852b8e58c1f58f3d4968cc886ea07d7f8953932d7e20c69215000f54e0dccd25e73d97fe5346f458da7b54fbe05fa3211b4f7cddf8b2564745d00e77f52e47c33d453ea7e69fadc56345d709b6c738a18798b9f38a95717372100126c74005153f8bc2d0f3fe3a2b7299d7319fb9023d409cb3a55714c1b7f4d00bcec5151cfe651649df78def9a98689ee746534f282ea7ec5426ddde3a520f00167cbb6bc5b18508a0c444a22d460ce681112d16e8dbcc52625a206feae39d002827a63b4b18bd6c7f493c612c025af36f7d87cfd83fa81e7e578fc238dbdc00cd216103e7b914b8516725c151435ccab6303a29007f05d32a1ca70d24f38f00eef6ccb1ad3bd85b24d427bc5c42f5bde22f4220669fc6f7ce8bd4f3fbb9dd0021814487ff9336aad90355bc56bd378054d4cb3c81b5c2577b512fea6bad2f002c71dee18aa0b4889bca97780aa52e6476e9f48f50e5993cf17f87d5e33ab500c99bfa563a2e777f8df399111cf1dbe36c53d1edbf8faa1346bae78858ea5f002e09426f7bb71f56c4876c9cab1f5bbea7d1ef4a633130efc98ce20763a46700bbc2aca4e87d5764bdb94e6deecd6b7d83310730b003758fe6a7465e2cd9d90018766ec1f7039f437d4c5b36fc8133f21147c2286c2b1ac9a9b8a5b62a4a7a00bc5c2f5e1231fa46775e0a6cdb779672cb37fdbfc791af0ec99a5ac9b1799800e8fdac8557f9e8741036fa2f81e3e538c4132135e51a67f8f3edce6c64de52006d61ba08ed8601159b9ee6020856b8c26a7d17fff55c4d4e22e5b21ae8a87e0045ece26099c8c0de44f9417f0b5d2ef7d5d685af957251d237263a4bd1e3fb001d29c455a2d4fcedb7378be68ef08b4609230361b402176f92689b4720892300dfc9d0f4205c0c4560aa031a4a59d7e7d13f76d199555dcee14af64efd8bd6006379fc5ccfeb0506ea687627c9a9e20577fd6836fb70014f1e165982823cd600f198df5cd9d52c21fa8a8f10b2a53f545d70afb1ae4c2de2baf9ea6b02443600b4f64da9e5343e8d53bf0a358d753159be02eb0579084f74d09c203868c297003a434c76394ea317ac8ab7427fb91aa41669b4dfcabac29cb988844bafbda400be8599ebd7346974ef85ec7b61b022e8e2fc7b5124cea5c978b8db48b840480054e90b85373d89106516dc4be5f9825bf641c6e5d020496312cb358d807bb90007115c806c34ec8abb4efdbcd2c42849642ff4ba695940ea12e4dac9bbca4300f40328b566dc819747763c21ca3802ed822a0bf4b165a7f0a5808367f0297600ef1776182034030f923b9a6e9b15f27ee2c568aa90f131745ec9bbbab09e9100dc36b3bf7f38a7626ff26548d1a7bc1d326c71d97182c31f600f729276f8b7004e2abcc4e4363a69d9ff8867a8d04a3c94efc7c40aa7dfac4188b866e57d1a005759697fcb6bb9a2c97a6a0965bd4122c4bc086a450dc137e42b5c40cbc6f40019b2e040db33380791f5036161c7a0d7676d7a123a4ec6bb840432d196fb8f00f1323bace723e19477d36162ca5acdea72d59fd573759019a3433ae03f650400cb6896e8630cb8c47bfb7eb59818c500d89ec0f3d2149cb20d7adbbc2391a800fd677a3fcfe40f2e664e49e34d2c978be318dc9c5f4cc52677591d612c8b63004eec83f68dfcd09dcedf2d3b5d55a5c472965ba801103a696c34a0039b7f620075f53a544f77e33cb5aee7b26a36a39a8bb340222729657e97fb1418019bf90071379fd946b79d90b5e79e96782fea582bbea1c8a49368de677769c1a01fe5009419f8a1a0c5e53d45d3c5338a5197d4ac731539e9dea6e4a5a5c6888be16600b6c864b77c871f5f36cf5a201ada815b4806ea706a7c7d2b8fac8b6eac4d5f00c08a7e49340b6e3d99800e4b9f96bdf4a11503ed868604172447ecbb01fc8300562b120cd21f029dde99fc0a4096e3d70018832d2ceb8536a531cda9c88b7d00033adb7cd0ec0e19b9d2904abbe042662e3281f24ec45971238d9771d0856200dd2cb96cbcc6d18eb777e5d9a999b35e540148ca22a150167941cb192e5e72002908137dff8bcdcf995980d6e3bab2f5e5560075d9d0881e733473372ff67b00559fd2f116362b4a33783fc536cbc202b0bef062e6e92672c6e568644f3ebb0060188ff4b83592d07761ef285f0ffe82d0c9f373d0e3cbac542dd7f81714050071646b71b35eb4f3d0b61fae30aa14c6cc4fddc85006e588d7d16333d3aa88001c8771f58b812141734e85ef22460d6433ef89a076bc113c00c8e1b286f714000dae6ca085407e6d1a9af3b8649840b862e2f81997f699c7f46d8eb2881a8300858830f16b02d2975210383c257678bd1cee234be1228ddafe96d9ddce1eb100e36d4494e1a2b8f7867164f46b2506e10ad912cd9c6f691bb6cc587b8eb6f7009321bba0e1b8369a2c69e962fe54481f29a8e5dc1976853f95aa408d3eda68004fe48de08fe003228fcc8b8584f507bb6e9cd8833c6af8cd2d909e4cb7af69008f1dc87b436266f8455462a06d211b6b6ab0d222369522254fcf3bef3adbe100a8d4ed31b956c15957b5cd3fd2fcba052eb616dba0e65b1d1752f8ec24f7a700d5991676c7849c1676f6d395833823258dc308291583025adf2c02d901ee820052069134d4dbc5cf279e2092c9680fa11317d8847df95cd9bbdc4e92684dcd0057886c8b838eaa8755200ccf618d7c162e3ba8ee85e571440455f655ac62060094153108b93c6de473cd4c32b44d06c7ab91b6cf03a0678356d0c9a718910f00431692e27d1acbf24fb31237a8e12dc800a415d50ff22013701911d912661b00dfacf122985ee39b1b780162d31d902e9ee29bf9adc994d114ebb83149a704000a6299018df64d8e37771dd7a0153a1d5a8b3b197f7fd28b5453f140c0d70a005ac216b4faebd3c0a77aed6a0743db02c642a7e8864c5736cbc727404bf51f004fbd734afd6b4e73040e7a55378a8081c9efb2383983a937228efceb149da9002ac48f444550c9b91f5960662df8849f0652626fee7388fa47e2cb72502c4a0030e37fbef5cf219e20f00caeba68de8f78e9395c1f2db0c650e1c3d971b13e0086c935c1a442ac4160dd3c39cd4020a79d2264834847bad3431dfb24ad0fbe00acce7e058d76bf1062bc7f5a2d968b46b5f2323a22dd07d4e061a95c8e1ac900f8d13480099f27daf38d50ebd294129ee49fdae8510eedcea80997f7677ae400cd2e7504a15a9a5c1689cf32c5637cb40eb1197c2333753e8347fd54c228830035a226a780cc119bacaa6f45b7866c4b2d14c438dd0eab13e59a5ffbf4284c00f656d1f6956968b084eacf0b2d79bb8cfd04739228b6828c5d686192d297310094ae52d805d69677e83206438c423006ec64e695834e69aeea0a60d3eaf3c20084c995514180157daf8ae5d45a6959d164fa2f8f8b53bdc1149068a3ce05dd0038a8066e7e923f35eea71d2b7b7d14c881db5598776873c29b2afa421aaeec0025278c1879e0b488b75abe36fb2e25dbe7cabaf1ac93d0e91eea9736baaf25004fb8158cbe5693ffe297877b9460ee618e2fd0a2535ce1558e4669860e7d55008ace9da1549e4f69dfb4dbe37a36f37f541906c911f145b524a883b25b408e002540ffe67f8bf77a5205f22330cde4308ace93a6778eb8d31a89e8d5b6d09300bb42cfbc828f89d951d25b21ef3aa0bb5c05ced89cc475e9c5478ba7dfb45d00a11d26b8349977d49727b92c25fe0fc1544069612bab63b38fb50c65ddd2c200f014e43fa1c39c9642cfc9183b758edbb49fce565a88c0400c2c78c804cfa4005dde47e34fd710414be60d392257f86c4b1fb5eea17a9027dc125a9dcfb14500e89f0de397a67253fcd50c2b6bdc90eff0ef9896221acf4f3a9d47906012df002783108be35105461d7f18e89c15a02e591ecd4a0ca8fc8d7622951f3584e5001bd9068889cbece5c404c503c80a0412efee1b777cee68f94bede96150e2c4008b1f9cc77c1b729972ea4c2be5498fa9fe981f76dfe584a4cce408817a8ea6004d1f851183d0ab82e3b6b26b53e7468741882881aa7b8100a26adc99c24ea100e0cdcadb45a97901333019195d0abe7b1a4a07bfbc4fddafe260e1391be46d0005e7b7e69cd52fcbd0a9ef04e324b0bdb7a71ba76bacb9ec84289dacb3e4fc00c90047b3f00ee2869e189c0232be855a09b924f9928ab4a095ec83a8828c2b00dcb26e115385f29e8e9554ee274ead4dbc29b903a39f64911c09cb2b2a4b1d006ac0df159d6735b5b63f7674b8f427d04657397dac6cd0c4dc80b3d879322400198a398204ce58a37c33aeff811f108031773426b23865e13a6e548eee5db300f6e9c8d6c8ace131fc043d3171c215bfc076b61f9ed9ecfa7df9057761575a006d6224cf457a424b10bff4d8933f9f836c8dca4f17224f7accfe17222737770056ee3564186d491decc10127780cb5d27c9b2a8bd7d1aec39754fe0a26d64600b399260de0a3de3342104e1fda6af33438d8580ed1a6c38c678aaa8aeac05900b63c3c5c5cf5a0426f52bbc33f62dd58bb678f68074f3f647e3cee83eb54e900891f86619786a11a54f8204d4011434334928a2535167f79ccc43c6a02dcba000026e3605a4d07ad751fcee3ab36977977997a9abf83af819b2574afab096500425d3fd806575e929a043b11c16f14db135b9f5f61ed117d91dcd47c08dbf3002845879117c020cca7c0837422c77c22357755f378e3a42fcfef494c90389600eeae1cb6278265bec8f04d1268d28ec539fea0b1efc841657023711fc1dc5c001d4f3e43705236dea41e91e5475977e7168faa185053ee7b1cdfba043e62c000e4c9de69b557c17a07edde6f0f085177b8c414bfe053d03d49194910159bc2008b2306cf202c50354440c1081aa63ed7ae73d55fca5b3a506a3e43bcba885f00e38e3d279ab4f1b8a9fc8276ddee435ba85e24f1f8298d8ef3e21e4b12851800ce3630a0ed27511881f5c900cdc97f10f510bc6ccba20832550db187724c170050c9e27bfdc5a4d43b9613b36d15fa8da98334541dbc7de09b90e484c291ad0095e3ed00d73961700897ea9cb5288f9d833172fcb067948535774f47e1798100d55bed9527725199f0eb9f4e8f7aec38093400df735a6e5d127e183c569ac900de74e10f3776540ab47cf3a587cc636c1c1d994763bc1f508e09c1ad60e7860018bbf2591a4db0e9894429168fe5c5ab182da58a18fb457cb842312b74a088003b475a492439900a9efe889119b98b776f29320ecff27351da27871f15d75d00074a965f5af1c1f20ee161a9b95c370d02c91811db3afe3e566f0dc9c7f15a009477f2357ae8c3d9de7bf323fde222a629c1e5e5e1b0a3805d699a7b99526d001ee46efa06bbf6ee741dae30691fb0690d62cc65b45cc657df7752a6c9b1170052e2830604a2a436a255585c345a1b8f69e58622b20f2114f09ea85b24f07900226ea1bab77737e2f579b8c173661ec7212c7534943741657342ef51107e4e000c35fa9582b4c083b8b0d3dd31f00272d3ee43cf87e70b949bac6ffc5eaa1200ce4584fbc779943018b7b21215f7f0e21f64a511aaca445dbe0dc9e00ffe87008da1a67447bfe3739575b2783990fb7fc876c45133dd3b87284a51a815f3de00549e49810f5a3cc089fecd0313fa50206be90d597dcf6a552c2e5ba21b0a0a00e031235af9edff292b68d15e2d03273f740a8ce91a0a81e5268a3a4bb7203900428fa136baa74e9dbf9d9d2b50c77594d257e075312c24b5c97e84671b5fd100e0f826a0dd3a4d8534f0e43db40914b9477574498979a7f6210e4f4cc3933700d3cd089fab37f1229321c0ccf25ff48194a631280377e7b22aefd973534c4100a282f533bf013fdacde51c89fd031a3a1fd18d6dd1dfafe76eafa68939ba5d00a884eaa02747fa434dfcfc8236c803aaf636bd0a67945e4166f8f30c771f8000ba287617c2c37429f3ab774bc15018a27b4a03c786dfffd1c496baf59fceec00553b20cb20d7cf79ad27fd7ac079e3089fc1810e150f89d5892ef1720ad96b0039e3f4df715344437ef68e67b3e3f5e48b41f2c6ed0c221da5b5d94224856400d7873c5213332339eb9a16f56cdca3e383865a6cbe3c23f8db7aa4c175993f00c0333ed6df3bd29b9f06acb99ed14d383c9fdec36f552de5569fd5a45b88da00312cac8bf7725372dff232e5e0bdde14c832c8635107010132074c8bdbfe9d009981aa13e9ec0c1fbfb305b59f7c7228e85889542276315771f983eaf19f12004d728e799efe8ce142288b107fabb8884e48730e589eeb554584ea4f5db9f100dc7663cbbaa1ffadccf3c8d61c152920a1bdb44983d445e0d8306a487162c1004f13a8cb689be4ad1dfa86291ec9fa2a79750a0d639793c70e5e3d92fc80b400814442a99265020059ccdcb0eedbfcff4564cf583cbe77f2b7a5f0296ca6700002252265b875591025b8168097147b503e6cf5e792f579ef5140e15c1acacd00d8e1550ed1c361f726e4f0b098fc98e88f6322f7e0f5d19c755d64847ca280005a18fb81ae368d65e59180c50c2720cad74b857370d9078663156daee8f69900901045a99c5c2ce016c29e64c3572bd00bd1501d55a85a0b6ec06401f5953d003ad6b28024103e3b0e60a95f1116b6890ab7548ab064fd682ee55aabcc460100ca8d2f2323937ea1563c0967b1d9a84489ae6cbf97c11e2e285d8b3549afaa0069b1af37d9af90554a650774fec84cc6adb178eb69b44a514e938b841b0d6300d3d9a75b6de4ccbccdb2735588edcf5fff03e187fd16cb30637f45ac38690400c06204a30bd5dd81ce1ba60e7cfe5d397b76e609ead0d3b08c2eba319ecccb000f77d690f7c1915308591bcc50102742e1380d6dee9dc4a137815b9ea89cf00071e07e58c8e5aa7d5a9386c717e902716a7790082e5bb2af315a0b2afbced5000121927156c85ee1411953fc70156c3941f121a4abb89c21294e7b19174dc3009659380336613766c130d118116616722c8a5734b3d9892f57cec576195d21005bb93aaf65ae7891f12a7ec0ddffda7f0d33c205c901b0dd2ead97cb5c080900e1485b29b4f7c77a3dd87da7f1d2bc218acc5a6991d746d92dba54d6a8802d00ea484d559adda56ce746b1ff7dad34816d3cdc80bb501f9ed3dc73eb7a896d001852840d7e0f9e367a03ed7df9961592ea86ad2ca1bfa93f38115121f61d090056c9727830d1f6fd3b67eed63b6d20435d17068df9b12817c914c922d4445e00a84e14fa07d2782593f5aa51ad3ca2ba2a321d2f2f242dc4bb73e905a3615100d949681fdc3891bafaca80b39f99592d7276bcdd84a613ad1dcb34a99482ab008543351780e4e1299b7bef6c211919223b49ded65f824b1efa6728870d358e008cb90a59031ebf107873e5d20c43259f66ad922c1cee2d05804d9134890b8c00bc0738260dcd15798b1d5f79f5164c785efff6debb0fc660130d10d381426200f6a6f1059c31519fdf27addd971c50478648e3e00fe6be7885c657ebb1cf57009fff6bc96ac9691e792602dc322b440bdf7e9fbb1b7b3a1ee2b1e3ae5b5f9b0004c6d21e6bbf4893f40f00cf6058291139dabf32fedbedfb36bc44abbfcbd70037946160b8eb62e53dce5d4beaa4745875731ff11ef9b725e59fe546b7a2b30057ee6ebc8ead7b87b217a673f128abb12f01a8ea9a05296c408eaa020004250075b8d4d6e69bbe211eefe570859a3015916a4c2520409a241705fa4b5651fe0055674142f41b79ec8eceb3b46e4833032c078f7621c03b46235920e27ade8400de64846d0548a9df5d998ca88ccaaf252e9e42a840798220cb814c0a0db56d0071a616d0fc2b01ede9b1f35dfe90863a2e92f13bbd534e19ba301b56c1256a005d8a6ff83e19cdb871b0f8ee93284892988b50eb0361a8038c39dbd43c347900f340a4fe5785a7bb473f2ef3a2372f0336abeca51a2b42b4fbe9e480a1fcd200c6c6152b203fd87700398ee5a370f3ec9b33a321d440be1c07facd921f24130096da2faedb232572b155c579ba00f8a4cb5e3eb468908ee50ea8c563e9436b003c1f8d0f8105032b9ee97c0249a7a6019831e3ec25e8bcbf8a66091f696c79008c07a797eff4c6f195ec9cfc35abf1fd83f1f3d21b84061f047e81c8b5614a002fe8c1fbe81164f316a5d1082cfe63abaca4c8312e2324df3dbc8a3075a82b0093ce75121ffb69ad3b2f2fe2f96b60ae34c5a8dca1679ae0a97ba71a5e875200b2cda21d36139c48a7545271d8e35e8383fb2044ffde4a31f9284ff05462d900ae1dde6268a2cdcb7392a69dd4f3f5bf54f596e6a416194365654e8952249c00fb059760095430e0f6947833a1c9a029e0fbb45b5a12aa6830beed67c59c120077eadaa87bcc2d48371e1debb84acb24ebaf60924672c06be19329523ad3dd001c5c1488df34576fd71a1ea14f523da591cce78bf99b68a3dc073153b51541005edce180d96c970f3fac19595525d8cb0e199eb7f18c3350a14646f65b2d6700126af603f20a52d09aaea26590313c1b198465fcdf1e35ac7a6d504223bb6500c3a2095a494f9b53ab9bb7049b70395f2cd55aa0c9d02002ccff7d2b962c0b00e7837ba0d504acf3d066404266d64dc25c0b74fc6c5cb1b1bb415cbf839eef00f447852f270d7ed38015bda97c4caa5af34f488a435caa450e69a4b51f68b200f0f3e4376f23414a4b3b204cdb4b10d9dfcc29a884c343bcffffa8949f885b0016250101395aa45fad155d51104e3a1a5b5d3d70665daff17729c7d62a4b790014e5130600c40e267643cfa6cd9bc800e245cb0a46210f70bedc20a6bf68fe00d9cc1ca76ab8f9bb79d1fcecc85480f28888548b84b5f86f0aed624b891edd005a35641a4b5c6a32d32f64cda3d0b58414e19ff3630f14f3b15d84d10feec8003fc8fd9c322b9837874c57c888487cebe1de3a28d1c84946c52efbf14c6c9b00348f4c4495c7ed45ee3b4a95eedda3b20acb9cd21b9bae700f4fc5ef00776800484a59493d5effc5c551beb0911df58e5ccfd269c7f7953c16606b9356897a00dc8083fd9a528d14c04bd70794d8f5c619705fe7891b06f61209451436a876001c2ece5be7dfe02fcab3988d5e444bac6d7c72a8bf00d68f9573fc381bf6a100e33cc3d7387be8b2f8387c2b3f6ac95e3d70d100f4e03247ad7e7b585262b0001e688e18e0bd51a7fe2f963298b9ee790481df2411d230dea6872dba152d0f000c0e7a095a887f6785da100b94ee5ef3cee3b7611c8f0845f314b33669edfa007d10a76a312a3919d3b56664c270c209f2483f7a060c5c33919a83658b72cc00df32d1d20d2d634eecb63c1c75959d41f015c118cb89f35d74f7a439986cd1007697b22233710d604434fbe305194d80c89692f85babd4456187501265baeb00f70e34f9ac7ed0960a0945743fa87d9f66648d8d4d58ba98f11325920286570003fc973ee5b15b62a3e4c3ad6790f93417fb909ccf836471c5ee37eae6524000080471db81bf76583f48e33c71908c34c72e38a102fa1894196224969c3ace00247968c0634f57eb8fb69ec5ac57d3dea2e969722894f42c51dea934f6c58300cfd2c8cb1ea706df0c2d2161d8344ca8d548a0332e6f16c3733c21c1a3f4a40009fc64992c94a91ecb75e4682cdef5dcee0192be45936375d6f3cf0f1c315100afddd8c17d26b31698bee1d143cd9f4435283881a8fa848f12c46f8c99adff0096aa8e080af42f98489318fe6e0d3c8cfd5157f087f1c4f8689a0543c3eefc008ccbad23c00f33a9d3fd42fd8ad3c0a4138cf98572b8d10c9922afbe74e5d000c4a845768bdf3f6479903f2c99e0b5a9cb253b1197969f7c9480ba3c3510f400452cee753f7c72571f0af35ea6d8f65bc3ab550ebf25b202b917c8226e7873003744e70783df66194b43a79dcc5b074030f555328bf14d739a553d6a8955100013e305be380c01ff7dcd890db38784700ce970f98b47bd45318676a50859240074cb6d97687cc7a35801bdc8ea9a274e67faf4026dc36efa1f43e87becff9e00a0f34d26de79ff550d5a0f3f043cb650bfcc3b859689433fd39e185ba526600049138bd3ac7461201f6d098a13716cfe7786e2343c9047ee16ef6287796c3f0021bcd0bfa4a513bf32cde7919cffc5a363983049fd55b0447cc533c1ba01ec00c7580256e97456a298207d4b85ae8c8a68c954a12514af215dc1bd066ac4ef0087fa79dbb00a1f5a9bbc3f4053bb29e068c80823c4ea6600ebe2a7767b8f1800084da308b3f724332c8db48b329d89c54503aafeffcfb02b8fea1c3760aa0a00a24e9b3cac2b6df80a0e30094d4512a3c9f106366a18270e0fa3c42c09867100edcd31df617c8aa9fe792d7ca283bd023a0a6d33cf1c71ec6133f2f2a1c12b00783626e95c05ca9777e58fa43404d0ce4a3290cff4fabc6c4bd3f1a22dae2e0038f4d067090ea12cf6c39cc0c3ba4940c4f3b87a7c45e703c86a0a70a35dc2006305bb25962ccebb12d363801fa15c640110aa5b0160a72e207ceacb591b2d00e62aad8ad4f50dbc4d071df32e80d94dd2b78f099934084480745474669f9b00f173d49d810a6f1927f57291127c0e9c456f97a0774477cf6312b07f46bd7900c9e967e40e1512ab0621eafc81a8629d038133107f4e756a697c80bfd37ef1007f2198f3bcbbdd4a2d22a1f07a9f6b9caac9c261b27f9d5629c91f8a3c89330093fcbefda743def10075640c8e866420f73f7b27bef7193c9eae047df5f120009098ad1e1bd4c9d43e1174ef0aa9cf91cdf95049e8851d0fe349b9f263694d0084f2bf35ffa68a1ebeec606e59c83811245893fdc4b0167a0663ae3bdb4bbc0047118e1e636eda3e9ca6e29459cef08ef9fa4030916275c0fedf1698c249b1005e4917eff2b8c17bad3750509b8fd96cbaf74784a29705458fc2e82b136a9e009ee45ca56cd455d7edccbb9dc0ca52ea991dce0e949fd0bde16ff6723ab5b400d681564c5176cbcf4cad338c25b22369ce3e5439d68746938c874d94429e8400335a5233be4cc58d698c0e1e31076890c41e9f9b7ac09a617b7f46851c92ab008f577c913cfc98ee68ce8505fcd523324fd79eff4ee46bc737c28b9b846ac3000110550e406d10f487f9755653494d3831c2f01e1857bf8f03b3b2ba6e3e1c00409f870c172e846b66488580436650b63793102f6035d6bd2d7871e3f48491000450ab1c16aed26e03188ffe7235e4feaa4e5893cb8aa53bf5af22c091290b00e97d49980857c8f8ecf3a85fb77ac201323a4ddbe7b781e0b8ef7cce31ce6a00bfce8e52b89aa43be77b2b5c5b1554fc037003cc2181bc69ec3cd677f8022300e77e7c6289e648120d36fa73c4c32643c2ce45e0f7f87d9ab941e31d9c09c300b2d9817adade793053bb5ef10a1c853550e240425d8156989fb6880ddafc240064456c12bfed37a73c7fd99f9d87d8769f258c5876ff4c6695329bd778a4020084132637a19ce95fe5615cade2efb70ff6d66bfa0ccc2a31f1c445dbbff97a007180b017ca41d6ba8c5e629dce33c40dab823884f6cb7b8d7d425a1882fed800ecbd29191619523ddcd98ac3810f2fbe921b11fde2d74f154884a5ba028dfe005a5bc815a121c80cb8404c6da0515e340e56d81ec282dbc847e3941ebf07db00315a7df680de0062a7d210acd5382d224fe02e63099859c32134cdbd89c4dc00252f0b769b27949bf436dff7d7ee8fcf848e2294dcd30d8b01acfffcd7d2e9004b6b8b18e49995173c7db827c67887d2630cbca42cfdfbb6234b14a0717e5200fab9ed1289af84bfbc49bd41e6019048b5598be42a68bafc6f50fbb0eccb2300516a0843a081fc1d053ecf08a2aba7090a447f62dbe4dc36372d550f6cf0390084d7f2ab7f53bd824ff1485cdfe4611f900473607067d1724de1cc2b2c990300c632d82ecf959192d86b3be3ad1efe84c52afb4806e20f0e96b8e6ee00666f0036335db00c5e9b252dc673b65c97d5a18c7221d39de87116a0b9977f8b154d00ba4228d2a8ec9e9250b3feb6b7dec0b8563727d74369bf71166e518bf0b44200f40189dd655456005f4f8fbdef7041dfb95f24e63a96d128702cf9d06c5de6009e875dc0e14c618776adf98e0b46914886d0e7d57a7cf1fc57f753b32390eb00dc67574fd0c76f8b6ab835a0d3220f3822887a2d75f894a447d6eda9dec333006de68695aea6efb6985b87defab7249708d28464ab3f256531477c5af2cb6900867b05a745e094e548fb11861e128126175033798ff97fcfd85ce549adf81a00c9798f1c0bb3de295effacb34188f740232794ef4e6683e443290b719bb91c004ee8f30205738087b26eeead05d41638bd06c8e32fe0a26f98da607a908cc6006a5fc120177017f78c6d3c1dcf8f15f18d541a7bddb5765240f811d3e8a2e0005ced16d216e06cfa470b22190ed33d427d5a111e9522476ca1e9bf1b8bd35900df4ccde56b233b792fc7d06c024e9dec3655324fd3340e4d614d01c14bed120001356b68790597d23ceb9b518806989655f6de3c56f402ddc1e6d2c7fc01bb00b54be7093d957be98a0a2e7a50ddbac80c90e3a4c59bd26b7912c4681e65fe00620ab37de60684799581b14e1b7c4b21d43282e0cafdf2ccab926204652faf008acbbb56e331e27656cf684f1b8bafb68d172ab5352fd74580cda3ff2b083e003a3c273a67376fae053cab14d4f0ee76e051f2e07c487d5aa2d2ed74650ce7006c6b65c1a49200eaadf2de191c69037b9fe039fac3f63b2874bb5cb95d1f9800970dcd7641361bc5020833349735daa22ffed70e711513811b56b451c05a5b00bc797499587a1919ea5da143531dd6da4085ef10849e672d93c6938ff155b800177c713b53b1f4cea11d743acdc4c4bb7fbf7305e14347f6a74194a61ab7c10071bda21958564f4915c9964aa5ed4dcb5fecbfeaf3f295388455de00a1cce0005b8fe6bb4a5c584a84ea95ee3bdbf919f3a42207e035ab8a361e6e53c1a4650040d16cbc60a87ff4b3011a229f068d7aab3624c8fa348dedca23be492eb88e0005d3ab34c3a32c4cef412877b5ab2d9d42477dc8ce95a11540e3cf8905d42a004226286fd9f79aa6eca3442ebc5e7db7c4e50fcb0866a0c2bbac90808a26d100e364da274b0a379f117f799dca4c98f5abb3c757799dfc4ebbecd31f8924860042fe7d4a1cc4e2d3af2a20ab75e327b9de6c7f874fb9c458e2abd16b353a3500a5fee8389c5cf652b35b7f893e188b908fd2001ffc273a3754955b76d6d17000d71c4b286eff31128bb14bb42d3e843dc484950d25924c2f7e02a9384df46600814f896636bb4e6a36cf8f89f4612e5532297a08edea11e7ec429ccb31f297009f1e4906567108f4d5b29f32d6adb00c93216e7dd15a5145590195e3825f01000b0d13cdb9b7e15434c3556e8f6b66d760cb922d98a6bb4b745529fd0923da008adcedabe4abd30ca40ca5799d5f1accb99932237b8dd726339a1ff9b67224004d5a060d9a984c0e38182ac66725bb4c032f62a4257da4c249f7b5a63c4cee007ff8b7078c27f9dbfdaf72a7e7303904cf918f1add80e44b0b3f3c6302b95a006bc793ee99516bec68816f6b8148a250bd91ba15ace66c1ae0b5f2a86aac9d003b6894d9a43f83141fad6a4455aa8240afa83d20a5cafa12db7a8adba40d5200910ed68aa87b6b525dab8a12e8544b0b79a92e1fa03da6c4401ee2835b531700967e59a694d62c6cf4d9639e3325cecb8a7c23127f5c9a9bfb9ec99806fa90005733a58604eec934d78ec4d5f5b3fa1c5243f55c4c5431cbf7c819c2c8158a00ab9242fc43d534cf42d22c5b8482edab942c16fbf0457becba15ec4c9ecd8b00f849ee5eed64f7d35ec13a6e203bd428f1985b326bf3558fc5cafd66c433b3007dfeab587d55b8523568105d368aa2c635c2dae8b45809ea7c06aaa6f953fd005c26fe8d928191dff28dad3d24f8c6a74178d94260e8b22c3f60ead7ce46740019f8edeccb584c3df2d1f24898fc2f50b45b830b4792a51f906723f024b2890002cdf0328766f63c0b475e3259b948f1e8d2146d71562a94e2bc310f115ad7009b4edf2c7bac8a201f17a57d035eb91c1ad35c1e71802c923594806824c63800e36bc59c18ceba90e8cfe10a5590d895c4d444a26a4aa8ef4042a2e99e4c7c0040e67efb6d0fe472a1758d9851df167b4f7251a4840fbaf9cac2f408ce9ce2005402748ed6ce6cf8dc4ccdca375bff62fd7a064a87768fc1ac8d401243a6fd00883cccc2c4680120904d0429313c33e957975902d722715da82b3946ef68a30035a1fde364e33bbfd3eae2196e49e1e1c526f8ccf4b69c82cea3c9fb4718cf0098aebc0943bcca10ca4d437087e0ee6397897244aaa0b8f65557ca0e3065f800a70f9c860664eb9b174022111e8f616f3878d12cbd33fc8a95bf32cba61adc0022534cbe79ee787e4222fd9ee88bf8773759f2790adb1aa329c8d40a86486c00370b6b7639f62e0fa2442a0789bd7ab68d0fb8a513f7610c9b1f86aec2c69400bb9b6385795cb5c5ef0b6d3bb380dde151f145ac2b48407428f8ae22c42b990038e19b39b5cfab5ba18c46e2b6649076d201241f84fde908632f51e06fbf91008ded2c33304772f02eb3a17d96ecd6bc65eb345c8556fd836324f6cba2274200efd29a3eb4dc62584eb22c0fcd844f4356c1aaa195337b43d66ad9cb63417300991cca5bbb49e8629127c65934eacbeebacdd6366bc961f756739e4f244d250068ba3b515df2c6cd8a4569e8b88274c13299eab0473d50fbcc9ff8448e02f900eb7ef67fc6052642000da288fa0c32b5aead0902694285d2c6e0bd1db7c0c400bcf42aab66667dc217ab2316fb548f76082647257e3e4bf2a7a5efd95334500044b8cf02067517c08d27b988a4868167a18f877528b8e47096284a22fe916b00f4a34eaff4c56c5defb489d2b98af68f4a70c6444d799be60af1a5732bd218006731dda9a58ea143fbcbe039f86365daf306370d5f0940de86acbe37f9919800933dbf8e0188d11fb5327d07608ccfa9496a660f832ec3a771dc5ee2b9375e00e49c3aaf628eecdd85bab14be0d6b6281c1dfb8d5e06344ad01a5477ea1b5600d480d196781b488dba46d84b17cab118aa0d84c67f6235457d288a9b514d3800343df2d9b743fd04185f069300efd6d8893eb6587aca4af08d952a29ebea840054f634b8e480295b06aee4b55dabaa08cc25de53e1420456360aeb2f59c993004460c784ef22a1b6d68d6aac13ff169e80b6f261000d059db9eac80a5793ff004edc7f964ebcc411e5a69345d1e5b2fc9603cdb61f5c1e54b311a5dbc97f480095f2b9db41422fa42ac5b34160ca35f61445ee1b7026dbb75e933937e670e8003e798e184df2164eddddbc1b96b810cfe58757ea0ac53c3c038275f52261960028add582f27fbae169c9e97c7ee454356aafe21670c79b47652c69adb374bd00b9f2709b6597e0e7b9ddb89f2582e6ed2104d5f644d8eff95934abe28e6b3500cf94076ba1d6d842df855e71c7e592935e8d98174e95a9b8b330f04cf1b38d00cb3c3f933a76901586b6be9d0da962e3a0e8ef1f63c2a4e32e87712e925c2400ecff096aa5ae2c7856e3a97b74c688bd24730c8cdf9a1dbb5d286b99d29bd8009a8a09313658cd965e823fb986766e2322a9cd5038d45c802cda07088757b800de4d2b58d2d4f666b67ce5264a65ee7de77a07ad9be2a866a46c0ac775f0be00d466887f1e98d6877104afb9ff1fdf517ba6b149753fa30ceaaf85f61f83a9004c254c1a7da0e2a82c2cdb90587e95cdc3f05c9d1f0810de2719ec0564955a00349dd4946d204c4aa1e8d89a4378ae3882817697edf3bffd0b256b5b3dbb53004708971d3f04fdc85f9c620e804bec09edea7ca3439ffb16a09948a420bd5800b0b8d5d3adb91edd308928794c8deccf27f738b5883dfeff0591f0984c9f1f008c8bd8a10ceb3420adcf89496e6fee83c78c98f13d7731f4e413d2b96e8a0c00a32330d871aa72bbf906259ce82af22342b6f0c1679d0b987fd3a7edbc3260001964acf839edd9b8f1c298dfc21515b7023f3c9a1503c9400123d974a95f9600946fb127386693f210b9fcd4825bb6d22e15f07b8d0ab36dcaf51aa66e163b006d2c33c77d2a262edf33819b7b67197f3d0b13446d217cb7934e649934052c00a12fe5940c924353050045bad52151ce4d977a4f5cd592987df4aa39e6bdb300ba479f2119817345da5aadfd7253e2d062e127bcf3427609662d90c4ebf40a003a7af9739d194a0c2cd3188c1074b0d912cef14d03be03f842c2dc9d9499bd00f47b5e9783356e0666698cbd2b6202f06ae1f491caf3e20f97de7e85dfa70d0016b97a28abc3c7d2f2edf0740e9d53aa65a6fe32defa37eb7179e82fef41300047af1e6d57c00a39ccbc0ce30ae133b94172461e7158091ad13261074e93c30057360db1401f82b3ba58438bc7b007662994ef119555a1c1a35253047e545d0044b2720614f9584a3b325b724070b5df31e3b4aa714b837597ac0f39344003000403d4048d40d109ac7c50eb880151747c6d72cc8edc7537530470adc6077100f68c260a1abd15de19c3bfd9b609fbbac368ce7e5560af54d4a189797a44f800c339a184669197de603079e37bf8f38bd1b58a0be6b30cc132dbf153368034007b2be55ad56d28beebb3673c62d5db2e5cbb344357a6089af26fc7408407830037232590580117da4634cadf60a270701142762195755285150c4078717ad2001a0cc237b108d65a77a9f46c45ed779920503ed674fdf3b4560af7ee324ff4005cb8643f4d540673e9b7084492fcf6129436655eb95a6c285145e7f8e761b1008f1ebe15c23b6dda8cc5901dc371a406a6b6fe3a380b118e7b49349e97ba47002f4e8468ece9b6f957bbfa8f766f4d6968a19029ccd90b41e85125bfbb188b00cfcb71e04bf637631e3652b789ecb0016f53bd28bace21f4b5f1af840a048d00234c40dccbfedb33ab1ff829e9e6baa27ec22766f7a413b4d43493e9ba121300a5a8a501059a1f758b347c24259a2a87dd6e5cda916d3cf73f56b2e37bf245009a1dee1f2b0c75d7d4be09a74d8321314092e7ac345114b65425a16d7a958600d73bb48a895422d2a46f7367be261e95aaef79fd93656dbdaad753853f77660099654effc9a8a2cd4c446c29a1cb8711521f9ed35b288017c137df41efad0700274b306b00240e7aa8325f8c4056669ded620617b4a0e8f43b0d9591d2ca8800fd4c275a5e33ba9d43b13be2a658d329de2ab0797bda6f30e02551e06a2b2a003e05ac1faf05999568e424cd96be3b04ba0cd1b6d7181e6fee0869be7fb50f0025e8f340cb8a348f87c57bdbc6bc4f16a40493b16eafe658fec83b19945d1500706c98ce3678502275eeb03f530f3045895350add869c8b6b55b4f2cb8c28100fbbc3a404ca5c092e87e7f4af1cf2bfe2605be56188bb5852f67c72002c3010068e439edcee9ebe3c44adb33abd8e22bee17fc3d92cc53f145f9530898cf1b00b5d0dccec1d190154038a79f85fc5d1f481390a0842a4202ec3334761b88e60009019b6438988ac49df604d7c3d4e348a4b909459224ab2e2d48f5c519128c0033d3ba8ab633655a2b831126b15a9211f9f31c11d9ccd677de5c170ed82b3000e927413b7e713a7b06e1828dc289fe94a92e7eed47505cf38eb4461dd5924800e21a467685f9416044b22ee3202edcd22cabaf004a5a6a130a5434189c0ea500ac098a5ef07e49db9c32881b42298c0e80717b7adfc4bcdfe053bb0c03d9ef00d7a2157736fe4d7d30ad8c90941c720434e5f07e071541bcba5cb0a3b2a15b00cd43103d83301d53bbfff78315b767c906ed75a7b2834378d90279cfee389f00a571e306881a9b2060b518beb387f2846c5489cfd433f65e703da370899770009fda450afa04e6b6f3cf2236d4f93ef09600b0f865eca085058d219813635f00b05d7f18796163d29ff29baaa851aae790e6003438913777a1cad238a6cacb00faba470e1b979b615ccec70e36f9baf1f862d8e63c19e008a6db383f0e191a0058d1b950e20b4278c4e0ef002d1c8ce47131cd1fd2f62fe5e0cc40d39ae9180010689e1c0f7be5da98ac958069ea964fcfe4618b276bf6680eb2d67238526700818273b0d7201010c3032b115811380f258306e8caff67bd077ba71884cc4c008e51d8b6a541389166bdae962acfff3c844d6101c5e19c5dff13817ebea04200dd1555bfaae3dca06904ba0976eb6f5a63f3457d16282ab5050285dc67d73f0083a399b353a2f68f066377d8a8caee8cd6e00e969bb0c78c3dd41b2c377b2900e65e8df8da625835ab5fef1a23a40dc6cdbaf70ff6ffe482d35d7c6d3037b300d25dbac602dab9b916be10ee993f1b05a70781a39023e9b91809602eefeec1004cca3978f35b9d10abe1597dbb390c4fbdd9a7c95620a331ee29bf78f2465e0048e0e605ff8017c11eed66ce97e30d5a2c8646a3edf2812c65e1f5419da340007e507f81d6361a6d9f0e69fb3b6af11337cf29b6a65075c650facca337413800cb306112b876a6f95c57a711f306a5cde8194f254d9eb2887bbe81a1bc0be70095ffc10c210d0143b2c6e93333e0dac005986de4246efc8cea6394a59ab96800775d4dc0f5bd9c45026250bd5179de9dc168008968983be12ce365b68c9d6300bf2c3c31eb73c1147f2c66e1a4f41880d070f716d1a3594d68d7a05612676c00dfd713b124c7ac6645a497348f380d684587ee9921340902f91fbaf17ce2b6001592d65b890f403b4f944af6fe926cd503d20698056108215fe53f4746b30800a2fd7d1a1ce807648933a17c73854b67849f28be3682cefcbc1e8579f809b0002810e6c11739f91899706788ebe4b3a75d940a39b83ae84d9e68141006ee110005620b9cb7ba87e24c761a6a06565fd4fdbdfaa514094c03a83cf51e85f8e5008ace483b2ed6f8a3c93782b60df7538b407a3400eee6dbb50224b7d60a16b6006d3c50de8eab5ced0af1b77e3b2837df5511acb195984f0a313d682ba69591001a8b8a82829ca348aa1875d7c6d69e6af1c9b6017c34490a6446cf2dd615d5007261686a4a6b413a573e9c58273447ffcf51cc51c9a742c9bfa1e2159a36bf00618a6522d65bcd5e6deced4ec84930d8c7b45b2ca53d8d359d55578de1486000ccf9caf061d045fffdb4360eee0ac680bf41472b452a68cfada08776929daf0085f1af3ef1a1b68e76c12b0f1bdbcacde63ae1350739c7476488ce1c6a4b60006e193b301c3ef41006aafc984b259ae2e5752781e6d938b36726e6a17fc7d30028e3654e3b03f4e40314aa8c620430cfc64ad304339d41b6532f1465f6016f00417a9b9afe79f2c5a0d43aa7ecf02c951f4f0d056ae884c1faa712aa1899500041ef996e98c445c372d9d011aee70ad9199bb7535b96a4ee98c90d7a9b652b005dcd356cc2507a1394f7bc63780f114c124128cd7ff8da4f38a130878844cb001cbc542c51725cf75b5a870ac356801543d12e062c2ad31e8cec0ce3b0c7460023141cb000b1ccaf37d8c3f3c5aa4e806b3d31be5fdede985f098753a03fd000836e0399e6df4726a241325e0a822f10e1e64b13d6f9800183e4c528f98ff600ae07ad9dc820337da10d75a95f99c833fecad0d50d0d65ba3ca06724f138df00902c48645fd26d6fa796f1bcee4eb96c9e50f1eac6016195980eeef05ba29300f6fe605ffdbe5e08468406c4cb54209548b05084dbdc0e31b8a0510ea0407d007bbd4fcbbdc65e605a068008678016da56dd85f721812c9111137a1dd5a4d2002fb29cee323b6d501da19265851a100cbf6071955b68fef650144ae5e6ee1500dfe9915f16cd90cb9b37ebc586494ad354061401b2420eef74a109acf96d3e00f8ee76d133840f9844b3aa0bfbef539d8d5f745f78400c6948f03fe7728c5b005a7ff27dd69508428d7e39cce9345264d38c9dd34296789d0271b62d8ffbc60047b8590102c8fcc34ab1e42a6c94725bb89fddc3589961c9dc90a0c383fe51002109927037c1be19ebc30f2f5b34676cf6413782f045b08ee8b58b53ff2229002165d12316c03024e8f8cdb7530d4ca6909d07bc86f44699fe7083c0c1b52100d8f844db2070d43261e8716234fb22ebbbea517549cc8fe6aed7978c35ba0200a9d54e9cd6adf57624306e8d2203e386cd75d5b06d18f7b1ae28586e5eec2200e4fdba7f7f98cc0a4def6604f8dfc88d36b6aeda49a79c3807994c91a85ee500e8cdf24d18aeed454cd877ec3924518982a915534af07d531bb94a74fd30350065561be52cef7555d5c3432eecb1ef3ee80a1ddba7a70fee7e200a6004951600fc697792a1400de4dcc2834c9bd86bf44f074733892f8c539ed2b53bff687e00a2796ae8fce84fe9651cd996c3c2a118b170a70aabf24befb5724b0dd432c700badb2dd77f8db2e5fbedc9299d1e144d95992615c27b1c7bd7b0a18df7731e00eca00e5d780fae7f886bc33544dc2e799f9cec10a2d787d15afaae756ff57e006cf7d0a1b5071418f4418575eb711cd088576a8c2975a43b223af0bb4c150a00dab1955c697d7afffa67b163c5f1e98d804de6cc875bb4a65fd444e66ec29e001097eb7b0a8c977f8ee4e0d25f94705217cc8032abe14eedee0ceaa670371b00b65d0a42a11502a7912dc0c2820639356cf7db1b9ae0d4d8b65d8dd738d53a00472179a59612fe2ca665ad6428245a9fc06d3de9a7d3f94a1269db73acb7400044d041720a3d10952a6d6bc5d0f9e5a2f9123eafe04c38ba4db24d90aadee100e55012aaf9c60b6e019da5cc6f69f3c2b2a5d8fd6c0903fcfa3b68073c410c009f1628efdad0382a211ceb301c17d5757e512e073fbd85e8538dda04a7962600944b72920cb9848b1784fc9e815c78f95f515daf9d6d906cd353aff2138924002eb4a038354040ec06059bee79abe4b056fcb9f7e5128fbd81e806088e19830099b250562478363d5b45bec5f648a52a33a518b35f8075bfeda18e0bfa207300d8eb4b5cc24fa59ba60aa33b1ac1a27e2bf34230361901f714a2f58ea475a200ad93422e02c1b881c6ae1e40db5fd1b3c9efc00ac0f156610967e83d5806590092b2e72072533fcc2307d988085ca6da654c04ffc67dfae21a984c0b5a9e3e00f2bdcd45050a9c0983a78e8ee94eb9625df93b12d8416460ac00c0c0c0a0110003ef9d5e316eda01d5b6d0b951d3124384a56e4056bf7ad24d45978bb86dc200745541bec163f5d3806bf7b758d45bb3846854367514f817b54796747f2b1b00a6907bb5250d3bc72ac51bb61bf6f6bcce9623a2487b229df393db4af9185700724835094b79cc15b40ca170cc0d1064317472b22ccc161ff9eb7793d45ee400ff3a057ede4fb86e53ad891bbb6dfe3c1598dad1cffef4843dac37402bf4ac00a02d1953077429b18f2a66482527f32f2e566217c08d991ae8624b9530967400e7d9350f3268221659b3f4fe4fbfdc8abaff20c3fcabfa9c8f5d9d004d55ed00dd68b9ad051aaf51322633df92610638c5de49b85cef9d2794d6545bc5ca5e000652a7e1caf518ae7988f0ea520364c2639857f91b92e4e3ba410935625ab200a260cfe2a8aab46b0c0a0a3d3ac232e4db625ebd51e375facbe7528a0222ef0052e9e94ca176d50b7b39d97624f86b93b1f551ddd4716e35033e7dddf33812009c097328e8da7794c4f98222bda0e3eb595d0f83ab97dc84eeba950f6c14ee00e6409e797c6f20880db8fce5f1c1840a318b537132831d185f7a706d799fcf0026266cf744990a3b831ffeba6ff6063a6442a7b7de104ebc43e4b4004c5fc700ac8b89401ded475a1b376df494b8e53171ae6e7c58df93e995ae608871b22000a1d74c12c417c08721cc65b2fda424b13faafdd5c482a6597b1fa5712ed9b80022e7a6a9bd291867bafa4353e737429620e38472c297ba791a079dddbd2d4b009eb6ae11203f2be8930abfa2af17f4c9bb1e330751f4db1a3cfe590e6c72d500e8b654a2ee865591c9684e298667606cf6b999958d291c166300c32900e4ce00d0459343d96bf44e9ecb5c2ff2fa6843f13d32d7a4189a36858e68a6f4741a0046272452124958d6cfae13248232faa3f96a9f1e56abfcc07b34a1d50300e600e985613fd7750ac33b3605a1bab4ef99f2943ad07b0bde7228b288b9d06b5400d5d1f53e19792271173fa173dc029f6ec998d0580903a97572ba35d43218d70095efe594184108088e32bf8e81caf5c6c9e4c5d8b9611ac6caaba135e202e8003b01fa8e433f598dfe432ea62f0d8d8c9e68fc0752ccd51f99b50b9869788000525b09dcc52b7c6c9e75dd73403fd9b59f61e04b0e2c4cb898070d035dc887002b96f5e49f1d27cbe43cec55b383af7a7eb2873d19b5da660a92ae4bf9752e00bd66d43d1cb49d3b89e9cc75eb960ff7da20f66cbec2be268fac1d5d1c17d100f52f6a1149c119377191ec72da12c59be8b92d847e78ffa43fb59a80793358000f0b3519cf5bbcdcca2cf4b63d6ae24f8773bc3b4f1d50bd93723a19e2281e0085517b86305232f41a72202cf48360659821b35c1f791b62e2d951ad0ea17900c09d6e4426cd6c9053a0e03c7c0207d82a1316d8559333caad0da02e72b5510090deeb9250d68681d34e533a35f8fc64f0364bcdfff6852483b762d4b4b114009ce276cb279cb8bc3bbb333e8b842fa2789cd3eb18a6f188d8bfbdb041cf50006b8fa3418440c70a5610dbe83c6e5bdca02baeec69af4653454e119bf3381b00b60fd32bd5289823d7f1b159898aa6b4bded3b4cbdc2ac768db042d52d0d960003e65188eed31bc4f958b1e8ce40fba5c3f67e4ede309f0f816ce016bf29df0071b6e2d2924507735b82c962f02ef716d08db15af8b6a8edadbdaae867024a0026274edd8ac3e9b12fe273201f4a1a93ab3fe056df6022d2af3563e3209f3400b26b41bb2fdb15d8f13193c042ac6cfc627695b0b5c1a681c23c79ff20936300e3b4be62e2bec0d3e4be865c0f24a3a1bb512f76020b3ab4cf638ac510781600bc3647ead08fc37523daa74a4ecc1e0a84e2f86868abd0c6bc4062fe99b4790030d5db5f96a57571fc0019126608b91a5992a51676d22f3b544921a5b0a56f00d39dd6049c39230d32c1d52db662733140cc54b3b0a198b47a787c4776545900061baadb65bcb4fb51e9352af4729bda4529136ddc4569486fa947b32a1db500961cf6c5c24d9cec72459a2e6a62cbb8027f0dfafb5c57820e144e47db9adb0089d800558406c230475e7523d0c1d965f3d6bf83360416d2c3e2f024bec5be00c0c9a753d6d8f7b8b085da3011ef5b893387b7cfaa9bc3819eeb6a5112158a0043d5334bbbd4a88a5b5d37d5e0466ec5469f58fa23ea9816bf8891f408469d00c136c72242c494faa3f509adb2c7e9718e4c0c0022f8e75afba24447f22a3500f8992efb5ae0b2e6beab663534ecb37b91d8190765aac1f8559e804995f4360012104b4cdb199b62d4fee078ac7f63eae8e0faa665e1a07ff9f3a338fde69900aa3efe100bc1a6dac3fa6c05878382a27383f126d32818d77bfcbf9e4b7448007a18da17f056e9f09f7b1acef1e78062cb6bc483ce53c7153ed9a99c137198007d406f4a20f6ae041a64ede5acd07c7845619a596aa62e61180a120c7fc4570000dab0bf5c9642b79d776ddca83e52f2ed436aaad4aaa9a90526e55e6b6147009b7b720184cc5635b7ecdb2a793aa37eb54c6e7b8d9f43a37e3796a07fcde10066c991394818aff9441b726601ce8b2d854402e0cee76f51edb03787a781e9007e10caa0d96aa414f1a70118980d8774631c10b77d208077d493a64ed71e020065ae1ea7ed0f6ee1ca2b5525e1a3af42a5bb5ad4eee659c61e7f0c24c8684100385692579385976213352189c57528ac6f068005ea7eff15c888a69e279df00069d860b6207d66d2a4608934bd9d99e9248736ec9c294ae29e95192c73a0be000d3794cf7a286001b3da2fb34775f2aa21f9a5abfacd5c4068086af8fb8a6d00ca7b234f6676eba22a90303a8dcfa84cd2b1c55844e3bf49a034b7ad228d0d00cc312907a868883e3cffa87ec278a75c3b89cd15924b5780560bf3b48af4cd005060bba413171bceaf6881333f2495023a000db49dbcb73177b4415bdd32da00c3a575ddd73745a8b873cc59cdf322284c85c7f82f5d5af86b13e9b85d519b00e9929db9322200dc8be76afef0a7136334dd67b838f782764b943d9407bd1b006fe8faddba8de94a050c1a48dd066a71d25c1375bb58c388ff6923a15fb5d300e64861f02aae64508958cc9618b90c4d20bbc63425dd3c5dde2ff4576a4f7500a60b3e81b4e5349a3ba6f6384efc6d050fb7949c33e0813d8723b4cd905376003ce43ed3684fff19d11e370ee015b63ebdf853aa63959cd3e4112282b0cba600c355207b05ad8b62c2bbd8ae7de654c8ded1f7c6793195b19bacadc75e919b009cdbae2271320726c51e26e7d8af27f9be590bdeb4ebc80bcd2f3ba114072c00ef01032ef34af40ad1dfb5ac819dcb8b3cede29040fd3327b20c4dd46be4c600413bc490e6febe3f90013409b239932c77011e7573bddbd98aeaee3f9f761b006f04e85c8ff5fd2c1dd54e9562d2866cf27cd96157a5df8ccd932e7a7be79f00576b52fcd5bc04dcc9e38a9fd319bcca8f9c32330e319e26dcdc14a970103f003c87c80544aa4e30f0f56f86920ab2c7c5ef25f2d86d81bd82e9f7c1f203340028e0c3dbdb0bd6a8d2efbb2f780dfdf7c8b0504aebaf76f1839d2ca29f8b8700f221213cf5762b77d9c3d339410769783d234f548f16fabb34f37872e043d1000a126cfe4819536e2dae816941a77efbb87f08f01b3e01420b7ef5e8382e6e0023a82853c4a667b128d275955a9a5233ebbaadd39bab742a293c079a16ac990043292e913e8c58e769b4c9824ded7d6906204ef01fe1485a40da55c79c428d002518d37dd877186e978c220a9e810a27e14142a6e8e446e0e9f8892e13442e003824824339771440df455bbff4836e8fccb30a45b7715d42d9e3e75b5bfbe300112aff1a72c6c7b3ff9e80df018dba9f745b249207c7e03b4541e56ac794db0088eb305da7958e93220d9f04004b851c2b509de9ff8ec52046a8642642b5b5007d50e5c16c23eb96356ee169ab28f1ac51289d9d8175610866a9a7873d245e00296d98dbc6117537b5657bb29241ef591c5d7c470c6a83328505355c7e9c50003a1190ea21956c3b99b1a1731d351dc0f15800d44eaeedef677294e6a0805c009d7e212a30bc3891beb15f6d33fedf34835c362a0d1f0d3d438d52f43a9197000d785726159ed32d2fbff40d0368252930d9b56ac2b6dcef333de39f890da4001a06b84c7fe6eadce9a3d6f61f5f0fc8231d313a0f0e64e833da3972f1e1b5002cf1819ea7a5e0f7fc486b529d89b9ad9e6fb80e1eb00a699995982962a22e001eb8bc24c86e3a5275a659ee5a7d4e0b3ae590a517e603fa89c18211a1d8da00f23b5290f0bf5b46047bba17f8a2ac2db1a31de1384dd91b009f0d8baa2d310036ba25e6ba04132ded5cf32a651e5945db0a6b34fe19c383a64ce78492baac00becf3118df309e0f99e4480443335d1c1ed5bef576fd1f16fb64b5c78e678000c4c4afa359f807acc34193e4cbd7777f0aacc0965aad67ab712a133e8e38e70025cf0753abc13094af017da915e27826d1c99a76c0858332810b6a01a4f93e0094ad4a7b15342c45d684b6bc1251c6ed6ce8e50bef3f57828d059f7637440c00fa1eee68a4b3453555954e6c96a9f6fc5bb1fa915e654dfdc9e120d8a960720071795eebc73ab34cddd3a3bc3064eabb4263e4529375fee62351466e6eac1e003e454273b22d827ff671f8f1ec21cfef3b0e11368bcf2250ccdaf80df9b26b00da4f9fe45f25e311ffeac5a05a04cbabb76cc0acd56d37aef95c426774c5bd00d0fc2a89f9bb099d6f3fbd8e2d0f6746044141ddac4cfce07853b1d0caf5e1000a24ccc9da47d5256ab4a69c364c0c62ca9914458df4a2f0fab2f150a95ce50008b0a7cc0d4182248caabeb554afcd9237ab065d0d10e92999aaec0277bb1200fb955624ff6c6c2097c7d40e5012b4b21520fbdbd833b4bd9e3e1023fa473500729e5b1f0820278d6da27e3bee52d7ec2bbcdc07e4400cfe8e13abfe4d164d005b40c49ae6b908550b485de397a01904413e8328fb7d54c1a69c1cafc73eb7001497ee9964546aca48b717a4e80a341679b9d63379c60302c4cecc10d3467100776a1f057fb6207f75f4e915183812529a23be8a871340fe1c204c2b2086ff002a1e1a739a0f392bfc2cc544966ef0223c68d120d6bda162bddb8e8dc5aa0f00ca33f242e47f51594d30f25d185cce3192813929ec3a9eda9842b1e488e35f00cfcf2030bf4817fed2d9dfa8e650b73f5ed46886175548496e3d21c43d266d00d8d5d02fa4d6289ddb1363df47d72e55c387869482794424ab718d335fd3d900ec9e3bb43e50f33014118f0ccd7ec246bf0ec27bef5eb9345cb50c92fb256b001d2b2530bcffb63a1294aafab05964ec6e065f961c486fff6b7d4d3e4f539c006e1f05f4e6713367d78c894a9c6cd767530d3800370aee989bab42fddb4f300099f8dbac41a05d1142d38dcb439be8a94cfd2f5a89c3fafe0e5da859d46f78005a59202c0e0d40fa15e1c36248f23b953e19ba53fdab5ca0c6a41161ed9cc6005023a9aba4c87b646541912fc7f1087fbaaecc2ea978bc2dd00ffa65a410c0006bd087495a8a8f70ba2d0e6a463f1ef0c372707e0702c29820157c66f1b401003e5b571e48714ad403be51aeef3c2a359e01ddebbc85960e8d037f7a133b84001abb970b9fc2f02e3f6c91a935afef22de2fe46c13d9702e263a63333b38e7008acd16e4e40e39ef98072d99600bfe9a86d80a738b8b7de1b6fb59691905490031f6960f05b859461d39e91d08854baaad0e5e78c2b27b8d520a61f4eaf5a0001cd4fb26cd93dfe0f73fdfda0a5f2542410ba40a7631b2ed624c8d73721aee00fb6fb41ec68deaa90a2a34610bc97cc46c0dd372e4491d42b1f634c15678460098a8c71e3b25bec493cbea5834489c9db4fce32d1c0c452bc042f7d56af95400c14b52070a09fd5bed5bc90595fab97531ada6ac9db6120d4c5d253db9e1a90061bddee82bc9a663a675043a72a03d569e08f83beec3c2c07929b6b4fc26f700513ebf1d67c85cf43a96e15dba2b742d3f70941659499e0fd18ad98f1f613c00aaa82b75d5b900c3f0c35e2263884c3f913ff21703446b589490ce68d810f500748d03655ec5a012fb27dd3fa743e4d5d3192ad6e774e83e6bfb072ce9cdd600d58b4f501c26738b4e4053efbe18466c960703fb7c247ada1dcc71e0dac1a300eb4b1359aab0e7fbac93ef7a9c82b3d35702900f7fdbebef662cc2901232a200c7c53171cdcf2f0ffd11362a4217b25dfcf6bd1339ad7e6e3481bf4ccbd24500bbb3f7ee513f6143323902ae9e7679098426f71c0d15def84904b836ca17e200b4e278088093ec12398fd8c6f002f3fd4aed201b2d4f7da845b654411c3c7d0079ab6fef4bfa73a9199ca5d1f30f746d667a01e35a034e2b10c40ba507ac1c009cd2bfd92839f12390dbf3abf7eef89a80f05644d2721f5020ab6573e2382e0070b1a51182163235c342711c76831c32253273d85fe1ca405dbeedb7bcc3510048f84552cccc0110956c6ac2b60a5eef2e51edc60c14abb2580846c5b1ff0200e38afd9040799773b7e1db9a5b97649a921ab33c5b7d56eb28147d9bbc7553007b31809febe932baea64af37672360ba7474e3c081136f0dcba219721a3fbe00b2df2d23d73badcdc3eb8b89c5620fd19da881ee1c57deecb2ea0779ff694d007d6c29990cda595db7d43f1dcd4f0475cb480a0ff0232c6917f83df4ea3d2000ae64efe69bd5d5b15a2eaf4add2dd12e03154ec664985069f62b0cc52f230000296dcaedc023e7a8ed63421dacebd54ffd1163a476e3182b3b5bf19eadcc9d00a04f57419c904f1f3abfd03e8ba517284ba46564227a073311f03a9e92bfb80084705cdbeed90a87ee4740b4115642a1f4b83ef5bbef7a14123045cc945be200f86943720c2bdaf238275bb3c1c38f50298af851bd2d39a3dcbbdb28d0b3f200de9d131eba236c4de857d16522b31ee9ecf10b5caa683cdfa34199f427334e0016a3e0781cf70768f94e96a55343e7deee49b5644f9b539a778e7dd4b25eaa00b6af33563e277ceedbef29391c213de78d8637a98a384463a095d14e7e2455001c9a0ccd1a46c635ef32fc88b7829b4245c024eecc3322cee717d34a31f6bd00e63cd5725e77811d664a0ccf98b04968778437a611f4816f1c0956ca18210a00dc5c9cf54cf53ae382eeb74dc207260f7748e109449c6df071b353fafccbcf0064369c358ad58532d57cc00acfb1aad1a03d4c6a418a0f0aeefc2d64b88c7200a7a53775c4a99dbbbc1016a605f596dcedd7a2defa01e132f6e279a20215e700a78def9cd7c282486df682a4c1a25d9e315d6286b40ec489a05e79ef4f0ac500757d34a97eb13c597352b5e5d73d821195d6f03d73f36072fc1b8a2aeb0d52005ed3e3ac6f515c531513f89b96c8aa2b409b6180a20c54a54fd45debc3d5ee007d87198ced65d6fd454d1c993c244e742f46e99ec1600d9ef8531d879d9d1300177b905543187667decb3c7977b40c2b367e8c66944eddcea941f771710c7f002ea99f98a18cb3b0d8c7fa95231b647fb46b439ac5e58d469606c9ef15726800a238f0ef8feb41befc844badfc13c8737a7e6fac8ce6f73005fc4afb11f29e00b6b3f4e14726e000d57c6f90e8397b1857a35d52f7f6882da9212adffba30400ab611f01e8a55d80f700b59fc518f02751673a270290cf4418770e1ebc0620003cffb14372ebbfddfe0efbf474a6313c624b02dbac81dc78ed8329f4184b44007a77b46c47dfbeeec62efe771cee510f4b4d643437c50d4f0df783a5bbb0910077cbefa9e01081a34c2236870903b0e51abcdc436e305053bd2fe9984d8e9600d3ab17af7c1208d4360f7555f2ee4c4104719095c0f0693585c6e2ea3215ca007260310fc5984da7c8f1222f19e9c5de6b69789de49c2bbe2fe665b58399d7006beb7654d2232bd2f0508ebeccf13fa68523428ae8ae96849b75c054b39b7400705989903b045bc8896eda0bfde0b030ca66c686cd585e8a529a3799f990a7004a9f801aa546f1ec14a9b2113353d758cbb4134c5d43470ca676716671655f001b658a4107673b2d1e0b5ad4fc56fbf8b7403574d05d9e275909473140ed9b00d03cd10ac5e3412443643ef9309471cd7f83f71235d0424799ff4235408ae800faf36bab64f36ff7305c54abe5e4a5d6c567d62e95572ecedcf36e30d481f500b9591c5042bc486659eed5f735b95910abe23844d07732dcd4de32b5d66c2200e4ee93d6b029c6602d4e0d8af0465061c21b720d92c8223061078d0c6181e3001dde01d11b1e92d1092c41085fbf4ff6e90e7539b1db1e06db5557fbfdff8d0051b10f4251e78eddb93dcab18dfd1a24e7716773c86f9deb2194bb5a636fa500844d6557443fe38940315ddc1ffa7dd04f3dc86c35ff9ee1e3f6e0b2dc04c7004446e5d1ce0a141886708a382904242486651f33f3cb3e62112120af77fe8e00a5eb4e5cafd61205afeb12a927e8bba447bfa5bb9f9436dbb6281c0a123b7700db913dfc5d633488019b8903f063401295038d54d54317b28d90fa0f943a5400ac0c571242832cec6d9f9a4015f8e79437d621132098b0da832a06026c54490065be568b132e195c9a59811ad2cb1a52b0af87c3b84787bad801957ff1937500bf8c55a62d74d81f1cf76af322fe0cd2f86f7e22d2923350e3bf7e7863d9ac0058fc791bd1bd7450161765b3c718e8beb80d38ad9805791e979e0b7f12619f006a97d70f9f54b09c8ad6fee827aa3287fd3a57d2eca0430366db497657beed00f4886436f3b9ca85ca59ba40d35d2ab775c6cd70523a75137c9901ca9df337007125b04ea8d624cbbadbf569521be8c0165cb0d0c26e25196a8c966e762ef8002555aa9011f230a2b475187a45477bfd7c8aaa0ac39cb79ce189425f2a2bd90070c579fe5a4f1c5cb8860b97259a780ed561e2c4226e09cc7a740121ddf18b006d7c5957e3126e551dde78535a271dd2d4a32c72ffe037b7217b816bbe030e00acc5a7fd5839dad78c1e5031bd1391187ca9aa020ec4fc42063e198202e62300afdd6a36e5fd60bf3da3a2e00ca5405a4e97871822602db2677cbb60cbc8ab009293a187fa86a48181352489d773a308cf3697354131d3b60ff318409bc3fe007bc3501a1890e87a110540528386f496a0d94ac728df74653c2c0b14ce05440058189c7bab604a620ef77c7abab742b869aefc0cc61f18e67ef7d2a8e98272008f500236736d54f988054d0a5bdacb5cec7f78601f783c151931d48eac5c2b00e0c54d903eaf3f5e70e538fbcd5f2639800fb6affb5f1807f4132a3cda10a100f9b9a0b74684a5883e0ddd303a6885a900ccc23b41d1e50672083147d4741e0032f87fc45d58ecb29a6c2133d80218d018d01a8b8c84591b4a187b8a41387200bb6abb5083feda70ccadbf18cd485a6af3cf0d751fadb426336ca2a2051bc700d13dee71ea8c7f852bfb5483585d9dd294ac4ab98329efe9e47e04e494564d006b36ca25dd087ccc522a76d9b777c03fb8d36b16843cb53d066db33287cbc9004ffa2d9534fc137ebaab5e119dec2a49faa3632ce6d3723e1e49b7f4f0d3860070d55556cd6132435253b827aef6d0e72fe50e9aaccdab1ae562bd11fd91a600f67346efd3262f6f3cbe925ea84a474affb4e38902c2ab1fd5fbfd1eba4e010082d6bb08c645a782e6b48a4344b820a45d81e526c2fdd78a6ee1900eb2014e00a9a45fa46495f4d1248b916df48f70bda92f5ddfd5ff3da89b81c7c8f07b6900db0dc6ee504d70b7de56a4350f997cae494afaf57511f3548d36752beab9890060fd9e2bbc012986d6aef749e242607dae4b94316525612a7ab9b599071915003ec4105e00dad91369fc2b3fa80c34346777664bcc59c6a4f2f97cb2dcb64b0091362116ea3b8b48c12b2ad268170a76e71842bb3458064bf6246438301f3f003b0ddce4d2c49fe90e0da03bd796a7d1d19b4531cc4f9db7601a2a95423677007fbc3aa964d4616f3142ce2e6e9374fbc58c3921ee07129addbf68bf1cf695000a6330e88148374df3b07e4702e829f7ab1d87d735b3cabb3750e692c0a0ca006080b13df801c286cf6f2a684d0b48b761d69d5e21a07e0831213d0800e61200f5fe8536cb6fd8303ff333ff4b5180ffb19f95b40f1dbbf6c31ef497877f0400a9cf2531127317047e6a9c952cb878dfa005871f224d2325f924b92ce1564600785957ee33662f6a3fc88c768838dc57d1678eb6dcb7aca021da280f680cf4003f4051bd9a60afdeadbcbb297c841a22ddca4c866054e90ee28caa0ae02711008c0a00a61d73f30a2168bca29764d4e8fe9e4fe5cd9a7d68012a793b064b01006a701714549c4a93c4e7d189ee739d80ad5594904f087a43762f0b066cc52c006c98e626158c52fe3723fe085b27e2416e41d831f01a74f37b6047c54a2cf500f2770017459d554cb836817d4ec1cbc022296256b0995ecf2a8d7bde5fa9120044c637565535d844bf051787973d08f7022384ecac55343bf246185f603afe00685fadc30639d7b182ddd8148c0736b490d0ec401f8ca8b0a312d64ae1c32000b3b60eb4ced4c431286a9c5b12399fab8377b776498bc9d868144359553d05007e1fd6817e2fe7ea0a3a74fb53144131ec3b222a4461801a17f1b3ce1687840026124adc8440e83883facdef6ad29e407c266602db36c54391c3e3cca1348500e514d2859d6aadd5a69a4f20f3b0139e20b78f3ec80b7e9a725cf952a8513f0099271aabdbdf7fce9a4a78460aee57e8fb88fd4d4ec6e3e24c899aa63d8fcd007003402c6a1dc66a134730335d2f873bd03dbb8448190dd2763c22b33544de00cd09e96b4783d37cfa15bbccaf4e60059f77424f5f414bcd78d2f88270f850003f38afccd74bb12f3b44c666755ee217c1391e17760a54bb461fded5fdb31500c6fd8df0b5c4e6b4230e006ebb6ffa9f4e539c610f2269ed93043014ce6c3a000f75b85504dfa711e2b9604b77e67e6180246ef848ba684194e88bf118e5e900d1ed3951beef7b8ba44339b43650a82543705c00c1274838ef1c5e2d57e9fb0009e9406f8161cf6cb5908815dd4044dad871dd16e74cc846cb46294d3a5d6a000aa0915a25554755a4496fc82bb7575551870c40bf791a3462f57ac00911fd00dc129b7202977ab2943d18b734819a4662e73a3e0553c4d6b0778c92c3d53700470f101981290cae511f9d5ac933e7332f77d863f1e8e71e816e77f13e139800a93f6f034cbf1561cb8407296ec18d08a990b5b417a8ce29c14382ff6a670700c1c19f3bd73fa4bb6ff7d59c33fd0d65f2a38c3387321f9722410869ebeb7500419b9600235aa3134b56b12b35465a8a06e7b3d65688245ae843511336a3c8006dd4129bf4cf7b9ba7db1c8db0f3e30c49caba2647b7a0bbde5d25341c7e24009598f7828ffea13bd61d9c70bda8326840f54f0a8af4a4324d645774899caa006b7f1deda86885860722067b3345422f19f5b14532f434d706b8206b14b59b008803b6bc75bc7535cc11ffa18d25302a4289b1ca6d2b8df2419d0eaca3854d0099cc0ee0b97eadfda733dac3f74b985de651e8d4a77de5a8fd40291d997ed300c45bb1678883083b841167054be6d7ab27287c09df428621529bb57a9999730023dc259df72e55b4ff39e54376c589f91666409ba215e894ae1d50e480c3810000261855153d1ac83f2c8e951bc7722e0173c18695daa2b7946559ff44f686001c57c6e2ba7f3e194898e98b370ab55b253a775037dcb746efd638480aafe700ecf6e06f24026719e77707f7e36ebe42ed17be0afff2766f7f95be79d6ed680029057048be0005a8e46baa95f61f59d29379d7f5966b3f897115ff21be651b0065750277430c0968d4ae1beb8ddcb6ad63474b03897aee08c41314ae3e9f7e006f8922959464fc83e239183f7231f975b77ff7be4afd0ba6ec6eb91e56976400154b6f97e95897c930a9ce2fddbaac77c12ef4f623239e8aac4cda8bf9378000eadc5ecd0b8cf193571ac0aa789cb7ab0eb59049e6771f5b8f9b87efa4eacc002f449a41fe94647333b30a02b5320a3b4fc3ba05be18e701caed485d202d3700158e6ed5dafad276b1219e3e712bfc7de2ab1b5c91443081cef2cceff6c5eb0057096dfbe5437bbdcaea05ab6f7018c2e1a88faf13ea4e723d9d753d328858003eef5755f7dfe409627c8067df30775ba26de2b53e0f984f4f0be482b2794e009dd1fdab4bc2d034eb81827ff1bbe7b00bfc642aed11c3177edba01f0bd3d900ff3ffae4b4987f376b080d4271d3b831f44745134ffa8092e716cc5ef6face00e49b5bd5736c1d5430b186f9a2fc04590f8183aaa15680254843ca63d91cee00edba40fff4c4f226f77726f95f4427a5b3b7dfd5d1b8db39bbd183484a0498003af91d6ef2ea6bf3e6e2d9a74789cdb70bb30de35265506d62329a82117f1400e7811236cc9a4d7edfc1b38583e39c67aa50a645711209b1fc81c40095d3ce00bf1d79c026934f37a0fe47189468a1ede96302353120c6eb267ada189f6e26003b93dd370a2628e9761c0b215ec90359bb3479f1194bd37cfbcd3a77ddfe9c00e2465c6185bb5a069846b6c8f384e1896cacae10fe94f471c8b5fb559320ee007cbc6121429ad452ba0072077d029bf9da0315083e012740ead460531398ac0082c418ef26fda21e34b53e774537c9f414925e0156026e2e6724de4078cb9e00c51958606f8da99a295f73552961042bc230729f04872726c9ece810b42836001433df125fee8aa5768417bd3551105e450aa579facf0f634ee3b0a5b17ec10053320f69785af588d2346bd549f2195d2a4e0c6475e8f68bd88c2ac10aec8a00130245a91dbeb879928b86e195b704f90987e329cb12f0f7a588d56e9c52fb00d5332a97b0ac1e75fe0ae7774a9ea785dec3f35ef96274d0c66a23773569330046dc571524b280f30d3d1296c3f0d90b80f4cea8f4e0df672d028026164d5b002035a91d6047d24b6be03fcf7fb130d9a722dd4f62479429e197a74d7bff54001f9671e044384bd444daf2775a08ce318b6eb99381f610632da2ae19aff5b3009edb41f2300441e5d1ae39992f2ba747d40668879314f8edc1332a876ead8400e0b98508355a4234987575507b272540139d54235c08d0d49e75be63611e3a004df272f960c37782230f9cfa89dcaa9d7016f545bb382f5135c80264c6cf5c00a1c64d56abb19306f33ef22a6d6ca55b919ed9084cd4cecb01c426061c11eb007282a3514f6c700da6c8e247610e1c95816b457de09fb102487f836d9e53d000455eeffdfacb10c0707896248d73f8332cc2a2cf1a2b4541eb9c474b8b03dc00855c074354349f7d027daf9d537cf3a9cf6c1fc9a7f69b7781d671f8ab3754004061d3e3adfb7660de7d18bfcf1f32b30b5b020c79545b4b57cfc92a3d0c3e003b3981470eade70bb2e97c961718917f7d8cd78c2c77ac42a42cf220738a7800c009da89d59218f467ba07eb9cf5e71c4b922a124cec14f4e38638c9168fde00127e221d8ca500cab7e4d9284e43632c95b6a204b12c7a8e1d62e2a2bcb3db00a23e4235e2d16b7489ee4b5c7c2fdb2a85d69796a911ed26cf1e0ae80c75be00261ef445d434367424aabf6e7dc8db3a8473ed4955023caba97b29c9c3a2f900a3214a6088632f746b653af37db96d9e1a966d4ffc9afac0a046293482f50b007998434cd0ac32858855366607677b1f3fae24ee595eb6f6064cd5946c66c400a4be54a2f24b837e75f72369f1f0fcc664f3f7421acec889a413e3a3170b1d00cf278b610bb70bc104aafac1f2959717a902ba02e92f4dea669b2db6aae7be008d088412f6b527b40754501bc8e49ed26de9da156899f5dbcbd5745867eb4a008d13faab90312791a4047480491e74230997e632ecde6f1db51b79b47ad31a00d054c90a03b226ab6c74d4d36fcd3a77e0e8244343ffab08a0a866d477355400895819d7279112feb132ae8e2f8f934d34d0d39fdfe908991604b08602de1100e7238eec3510db5f8e9e850c4cbb2ad61851c7ea675e6b4354ef3c4edd09b400200020bbacb4793421deac326aceb7b0c711dbb3a1e400b4eca15991bd9a34000c5600513a2c1bddb9ef73b6618397406ae93471b511d253477cf61058be0300a1e11b255f75e00da2b3999c1aa214d9b4cd91e5621c5157861e6d6725dfb1004affa647c9e61812501326f66c002907061521a67db1173eb6a2cf62381ecc00ce8b40afcf7b58e41734070c1f4c8b849b49577d52b857138f248af0db44c60078ebdd7544a8c230efab88b4632252667a31255c9e8e03d4fe36f669142685004d4c43a0565a6b699e1f7cf485337dd10cff6d230981bc759245f51b944875003dc5edd55d706e4ea7b956dc960cd78968bcb7cda8723513e5f037f0b6919b0011dd23ea57726b2018947c6ff0bca7300f29579d1bfee10b86dad740b634fd0047f7504f8ebef43085f5514c799f26e959f295f698c48766405fe4a993c1ed002d3fe0b4bdf2e4c89a034903ee7f390b89e0a045f9b6de33fdc4d4794989cd009d7a3e94d0efaceed9218f0eeef87b42d63da8db31f48e67b19cbe8452a3b7005eaac77f965167a3c445cedff0feba7b20a6b6cfc578fbb0d4667f08e7813e00d02d1155d862b4971a3dc7db6f0c5c877ad6699ecf2c7510fdf03e686e6cc00099ed537ac51704d4a7e150e764e259e2ef7ab8ea5d0018e86af5d2211bc491008af9a0103164c0869df157c9bdce67a364852352abd6cd64d5c886b0de14400007c746848225ae6232ca89b21ed41d850210802f398a0bdd32fdda4b3c2c5300d17c4026bb86b03b1e1835e4faf78d70e63c9d18027c1cc225ff837aae088100d6e6ea9b4e7a8fe1523c7fc4a9ce7105726a59a885c5fedb3ceb5692d065fa0015371ea441c01a5278739812359f22e4dbd1ccf5349a6758acb9552d8f2a3b007c3ecb2d615bbe75e5a3f9bffe60da133a6527cd5d04411c0206aef84f0ca80001ddf58d99ef75406767bba5a4542835e8039320d01928d8d21516b90715ae0075affe226bb59e2a6e7f780a0947b4807c76722e9cffde6e35b0c026c039550040c75302b9bf5030e29a91b4fdd84c454599e7bb9ff8555198d5bae507247a009a05a3c370e3217fa7126d073e8947601c83fc78768e98c1b8b02cea6ac61200e275730ac955b3e5f134f42404d30ead3cab69988ea942c1a99a85c47e21090013a9ce37a914ba23782d0853faef6f529e2a6148c5b8a8ea47713822a3bd1900345afa32a9f063c4ba996e96ab78ffb59f8ee2b9872cde16e5b54a3259cd4d005d2d4fe8c96cd4d7cdab299f8ed318b8a3c0adfea5351291295a48dcbd7816003e9d337e128bdb8848c265d4a24d2f2af8e5ebef58487bb2b48eec4dba32b700044157a43365e14415ec41e575091af9059d45b225f5f1e65cdd6c6bd95dfe00d8e87e8d09c41854029f7483b47d167bdf8a45e67243e43ae251a2377b6b86003f42943ba6e0a6c1053908c7ec8ee6d18448a1ff74b353aec8e5a2e1f0788200a4de52e4d14438a4b5676899d2f0b16a4829b85f95c503d522052b13d2529500739481bde9bb0f199e6634c7bd81dc8923039d7ae43233a857c888adf5084100d0ab29d1c26a20494bd835d9ea8580f3aea510a0865520cc03bc223ef46e5a00b84b94d75e2833aed977c5eb2469e3b8d00520f52ed339a5b32fb318de301c00f94ae7cbbbc4243770e3b0d8dba49602801a4b4fd681d78d49b77bfb987f9500f584df73f3d3c997b4c8c06cdb82e8837625bebf5b112ce2024426158c085500dd36a336fe79c10a83c90661068a0634ea55995eba249eb73554f768794dc7004a82e0e49ee72c8c42093b3cae8cecefeeeb4dadfb486d13720ba62b0e6a90009c6449b0f56bc54e690d49ec6ac59440819a08fc6f85caa0d41c1d50d5dbab000e16a07c1ee3dbec97116d3ea398e1719ba688be8e3f5f6160e1bb1c60a5cb00524c4fe4d7daeebdae17203b99c167551e720a77ddefb6a7c7d32df0c17f9d0030baad203d03de456540aa8cb59b0d2762ce92306e5a78178fca1d81892c240040c0250ffa4f22768dc17d34981373b677b4d0ec3a96afe54f82491885a6d1006afb14ab979210213205a17109321ce6ef98d63b03670ed4bf426e887e6c3400dbe2243666537aff8513ad7f6079567152e84473bb4c87dd4e860c1c1be38d00723ca4dc7ef1e12f95cf639c910ef6422fe70354809fee37db7210b0c972d9001fb73dcf7bb0b5fd231273fef6507627dfb50a0a983f626d03824add7bfdcd00d8915f1655dfa8c272b2234942fe83dee42218f6dc10d548125400445ff0b400d1e9c187ef7d956f4a58bb94589a8a49bb1b5d276ac34b8359bebe356f340c009db0e3352f7f9d1448b07013f5c251d3342aec064894d5ed3a9fdacef6edb4009fa3a188fa0aa359b006ccd29951ee240755a5f981e31db9d12f55c1ae1fe100ce7a113625424abf132983ee5dd36fe6ad074131c7cec5ea29e0cc1755eb00002b1e6d2bbc8a25cab19c85da20365ce74716f43865d3196fce911a49f1e25100028b7de13fc550a3cca9c095bece3d950145cc276ff93e45e1e18606f0a76100bc48f658578a2c11550a3e9c925774f3545a561c700cb17041cc6159f2b9f700f15d1a4ca0ef6efc9d9193228362aec46bd82bdb6388e9738fcdbbff67dd31004fbaf0869cb073eac20791de1d4218901892db3af73dcbe2bfcf4b50ad0f4000f282024d9ac89f88649ed6f6aa2d877091d3440490d789f9fe8c086aba65c0008a717433ef16166c6aa52c67e82bca52cee3472113d7e850fa70812112dc2800d9ece246ac1e68dbad058a838892f4558cd72076ba246975146792510eae1500f489b28c2e77fb80e06c7ec1a9ae740b6ee890b99f583f2a65b5cd9a5c168000f63aafac1f4967a0a26bee4642e8c8f60cead70ccf1e5af086783dc7b597a500adae47f5f7c22dd8e797bb5fedb418b0d35c6533f32edbd959f644c62801cb0074c85bb3da42389577c69ee0f0ad8ee8849cf76d8bfe3d7f7317b48e59eef3004eec2db00ba7073bc06bde933baac44aaeab8c00e148623b9c68154bcac6f000a5285dc99351557ed582ccf450ce456659d06f8602a0cf0da7cc3a8b5910a6005a388451792957da4cef3e486ebaf5dc63b43b15e65ef3607a2ef680e3dc2300b63bd2b0302608da835a696e013a4996bf4917d3749a6909252b0cdaca7596003bee7e5e5121395be7463706f51a45d57d7d579a423ceb1e28360d46b1bf310081aafde00f9823b2159fbf3870ff1c6fdbfec25e18e93dd5e51a15c12c862800ab2ecccd017d3fcbaf01c322ed6c83ec17a713528ada5d03065b8906be100500a69e23b55f70caf87c61d01a7443453c6c0f30378ffc907603a8eb608fd24400f5d305685a19da9a3980741dff89714407143cdc4bc25e1992e05ba80ccfc900fde77cacfcf882eef0eaeea51d0bcf27bbf28fc4bdbe42da0fcfec827a85f500a09a0c7072475aabb18a44d71c9de3084c1b05be878073854f2114f544e0d500f150b3a2c91a96bcc1c10593137869bfedf6643fcbf87e711d7871a392d189005a0e93590cd5fe7cb489f45a469fe9dc77d6a8a3973bf08b5d2a04d95649f9008cad0188b88288577443581bdb75e04a2ac6277e73b80fc1c12b335694803e00142aae70d1e09f78a68d5f47582e8753db30895992c2101332689fb8aacd4a0069b6607ada25a7edad09e69192857cde8d0af956a86afe04a673f305f81c6000c0164569b69f7086ce15ec66a2c96f7c0b09f15a3ac8eca1b725fae33a9bd600da1dea35c3ddf01c201e8d09e03b5d52ec5c95c02ed92c69c6a3019f5630c7004b9d68034cf0172fccb396a1c805bf280a4b3b7954d979ffc12e3cbebd846c009ca254566c5fede916f89cc334b0b62c1c2d927c6d9c6eb8d223fc911bad37004c88bd04e32f82b226e848998147cb3e508a0cc308b95ac2e957de164ecc4000e607fe3e0b97df98b12003e80ca374454aaf6d42d55ca8ddb423ff406d011e006cc9ff1686d97b38f24a9149b96d8336710f4dc050d88441351f4bc5857a7a0077d08b37e7bdf2eb8edc585cf285c3adce77286a916fa23a1cf05a14398ee4005639c49a2fbf40468962e2972948fc469911c66c173820a409ae8f937868900023b08d845fb3de8aa9705a2481ccec0850c4e5d1200f732f52844e600c955d00b983d6b93199f9ad78c0755f5ba2a58ad0955747f3efb2dea819503214ac1a00599f5b0bedc005a49f9822053c0cbeaa092f7a613fe977a38ae439bb15d73000b3a6aba0b53997688181683d3fe86f1d4f86c730370d029fc1ff3d3ab475b200e7c5daa6e4d042d93de0983e2d701c21f8ca4cc9890d05881b2553b4617aa80087472003bd5b253a8b106f8e2ac411d0e6c52009b101d5dc96f17e08e6569b00e5865af3cfc331eeec404a908647c6960cb55d91e9e5ad43b3cc6f0868ecd700e141c4a76969513af32db84e25510b0307d784217fd3d04e42d3fde4eb0beb0056c830a4671d5c6b383bd9033b3931fabea2969a7992ee54acecae72a5562f00f9f0bf51c61f60af6de51e47dc89e27b7d5f263f3580321c02bebdfcd7860900152a83b625119564602d20e5c7eacf04dd540b7c40139f7d286c28c7449e9c00765d4ac80a9a08380b9fc2d2b9880907a5c5e2a9896224957894726d35b904001e48aa68fdc32a2ec6a39148b979b256187a8657c8cefc13dca1b5240cf5c700eb57380645440709cd76a6272a9174d6fbef3581332a2d9a8398de1ef60eeb0028b716819fbf7b02072f27de27c43aea55f05b595a3b696af5edcca776049600e2af2874acb95052a5c24d76fac984991f7db98dc5abe2bc5885d3917b54a2002af75adc009c4bed7433fc460684f58871bb599acd8bde5d0ee0894df8249e00c7041c671a6b139521e944b6820211881f84e0516d5de7d79f8a61a3c480c70089eb0a810415c21d644866f4b330e1c4f94952fc263148fc5556cf46d9e1a20030b309d6799da58090740513f921976878a08b1502a994418f6ab075be974800c7477458812e994f9ca2316ca76f74a4b18a56e7b3df8c2872bc6a85b4cd4900647b87a325a94700807720531b5b8ea0f30c2b9b10048d08d21e8db5c837b00082848e8ebf8a364fb50c924717ecc5269777b53c4e0f4515d90f1d9538ad64009e189f07cab37c9c0ca9f9a44394a706f9fde09d24e392e3f0ec822383276800f58868116f0da8aa9891af141a9bc01f82b748401dd5f9e4965bcfe94424ad003a80bf5df46d3b7eb0cced1e11f881ac22956a4f24641b3343518904d50c8000a8df65b2459c986cebcf23587cf8b119ebf8d6e5d5de041c79e2bc01b4645800da25de1a999f5973eef0c35b19efc0d8d97eb990c14a2127b69305f5c0074300776b8a8a0c186de55c6c39040a482df4b9b8a961696544f283ce79215fd48600d374c91d18d90879603e9c5b1718a80c63046078009243ea2501921cc91209006d1f10416276efaa0bb6378a03ea0461f18f9e6dfcf13e1c948b200cd99c690088fbd6b678edf4b16f954b10bbdfdb1584d655e3409bf49bf02688b52d67390062459da5d49ba16ecfd1279cc2e62ac3e17b3c8ae6f9ea56748a1a98cdbf550036e54b909b22bd5379a5c535cf0d9d044b9eff794747ae911b964e4022421c0028d9212e0f20ba8b537db7c378307cca31403bbd8b5e6f9e7bf5019396fa2c001e13755a65ea73e809ab71976d1cd4a7f71f98f80738d545346d4e8392570b006deae09f2131cefa9f0266b8990eff47da8e0326714d69c6b3954a3f3d0a04007547c456aa1623ca2d41fe5bc34378c58fbdc69c6175cf3f7f9666369d9d47009bd6725904e019c4a6571cf5d80d139a0c2ad6a5bae60ddefb6e7dcf20259600ebd405332db962563b4b9a127385b0e6fdf0c242f881ad9ec64835843fa86d00d2b6ab2eb2aad753bbbe89bcff7a0f501b19daeb682531b05fd1c918bb26f100fe896b1eeff9330394380ca39e65f455c4f8a938432c7d93e3bab7420a7ea70072e72afecec23df17e0dd3cf67e49bd7d79ca23a20b5896dc70c47a18380c8002078e50bd6a35bfa34b51209d46c5a4d9e3de761350443cd41e952ab0e2181008d7bee3721e2db3311c6fa19ede89704d94acad2fc91bce498978f00fb894900b2b4a800f55b6a328ef0135c3c58d3df562f589a019fc6de2a538ec966e156003d527bd51a1802bdafbe538cbd6a80a5d30ba04f7298b64c618a777315e8c10072e59370ba60f5752061e2856a94ea921b06d9fea029c1636f9522f9362eb400cbf46dfdc0a125afee14f0adbc597ba0622d17e7dc2d6ae87eb3d4b2533aae0079473bb726818a56951dd34e6ec8c95a5592f5faa6fe3b6c26c8f0feb8b4d900e59bc85d2675e21af860b103f1619008eee8fe7491bce6157e7b50bfc33dec00e8d3f27e0595863569919669fb3722b5aaa9f0ecc9ec71796c2013c22e49f30089ec440282ea0568f5f3493280db2c30fced0c3c8556d07ee58dc7cf097a050098da822578940102114739e56fe4919d95a1c9cd11a43c2b08e1f457adf825001dc43b5d9132aad7677efb444a9343737eeb87fc24f0d9b5c9324d1d81ad2800a2847c3387eaef5c78800fa518dc743a80bace9b776b3559e8b53fd56fcef700ae3535dd172b10c47449f8b55c5c93a97595f464bf977f1fdf1b0a72404e0e00ed2a755dbc057d21bbe6ec60a363f753904094cdf55ab77c1a525bcae6fd8600e963a149ecd95bc8a9b4078b076c1e57532163ce970b3ae630ea3030facba200e2bd2918df31f932adc33d8e0870152d978be331d231276373cf281fb78026005f26d6f77c78954d70f6da1f7e3a4da81acde19038558c13b5ff48a85e2f0d00a467bf59c4140b6eaf1567ff474bb7414ff673a620addf056d60dd41b6c60300aafd3f9f541561534d3ee456276b692e1b73d70a8b2f7b8737ea3adf22747f0065b7d357b4ac1eddfb337916dc67a6343bc8034dcdc68bad68a6f1202b63380000156d8fb737dfd83829474e67b507f5698dbda2d1555847aa9201cc2478d0008a8560f2b9d9d2989f945b86230d68dac29c3eb1fb7563fb6bd0c07895a4ea00c9e0640552a53bcbd2e56ee692e92ae7dd5849509280836a050709ffd1a370001fcfa9efdadf8ee8f3604173145654b2d6f10d8c1a04c551bb971715d6f9d80099db01c9776a16f9457328828156b2370636da01ab23cad52626583d20388d00f90a213675169e97acfae8da714c1c5dc0bbf1ccd2743a30ccb0ef7864f4990058c252ab67156c28d56c9c6d6b9a4f8f9064f6c77a4467c93b72ed144711d0005125599fd0d1e68f5cbaa49fd11ee3b2aaa9fc55635dc64b1e7864d2d3acba00fa94148ae608dfc0d0d134c3a5acdbf2912a58b71bcf9c36024fbbf2b283fb0094a2e3c3766b9dea7ec27adcecf20722173afe33d2a9fa4769f79f34edc0fc0035e68bba6b2ad1218fd7b187ad509a10f2f6070497e5a1f59d7476772b2dd400528f7f4e8a02908fa02c287e41708bd04aa6c241685ec9b2595ea95f74abca0095b827a448d5f22ec33b0be796487b789fdd7a859a1dfc90142fa0b47435d5006a2d22d475983c43e10a3debdff46a545407969894fb19aa11500b8cf5f9d600f856c634f66b6ef79bb51bbfcae3705a622be8c4710295d792086bf2816cb200425ef640ccba8c78be018f3fec6694ca5a67a9949a63400a5ebb7712aa382100de027314a77bdbcd50009056e91736be2b511ab0cc170ab59d7e8c71fe8cd2007290023011fc15946daa1dc9a1a062f1be77bcaecb26643aeede5f296b5c9d0040bb8874bf6eb685ce21abf61c4e14b1ee8850b37b41c496d570184be4c462000eed13a3f9cc166a54d6855998329ca9f171655541a3735145f622cff6b57300f8e66bb72faf1b2235579f9583f209e0cc8e0b64bd70e0b64bd539dcacf3ae002a993613bec5044e9d7a2d364a8cec10f4914932c522b7255307e42c62aa6900312f1043549bb85d1747fbd11661378c9a831c0901948eb5a46669aea4500c00ba409b738714dd9db2663c63efa1ce73e4258c8822cd69f4b4d6b701123fdb00f12061b48574a69f3251ab864fc0dbb88a82de8c3f2a3581b8cda709d1e4af0064170d7fa30f43833db08500f713944d8dcd5f1962eb5f9f1a7168d397540c00397a68346377998952298792d4da3d0a2006f7d5520feb49ba43418c59cbb5008ecee5be27b70c531d36e78fedd7048f944b639efad67f8b0a70989450014d00140e1dbf6ff7e39786555c4f8dced432c0aed2f501f5095cd6e1b54daf1632008a08a64c5007c647ee6e15c5df58986cafdad3d4cf52a26e4510c40fd3dc3a00fb20882abc6f09bb164fdec30c1ad0381c3627da238a2190d2043f9eee328b00c2db084ba595aacc682290ea13d9f7670360ca1be3a132eafde92b1281489800310ba9979dab701ccf735353e3100b5779b6b512391bd9eee0ed49be60f12100fb2725a47852e47ed26485a733fffb9d03a0e740a23c36f22c57a687b8cc470067b4a80b1c9c44099863f7292ae4188f7f824bed026d51335254a1fd9b932c009fb3347c8d321e7b19de4a279430c43a1a50b15f2786139df6c8b8f31c42e5006a7e0e76abf75c2bf9dab0298f28d9f6a3824e3e115d56ed0b9d661870f55c00b74d287948c5c47fab01a87aeb684e267f273885af15043ac9c82ca69255b6008655d2f097252c96b83b8725874a1f8910fd411b368dfc5d2ab8f934cc542b0009aaee8691a7439a9758677eb9869fcb8678bc03a9610e3a761bba31e85d3200f56557c9fd94d32b64fa508271537500988922194e3632cf118b1e2b43c99b00674f4294299f526a1e9d1f410ccd0ef63616a886816a6e2cc02c6eb173050c00cd36d5d278b0e710c39183a22dfeed25ee3f2e742c68e610ef67fe4316496f00ae05bd8e559ae825105649580c0882582399a97305a88b60291d15d187e24400ea2b4539faa72e6a9670871115fa04aa704ddeebf7cdaddc445a5d8e9e172c00423088e6393c996553342b558b79b57e729341dcc306373806b700cfebac6c008d704977e4f436b7916eb8dcb04499b4af4f1b2febeb4af45c688454c0477f00b400479eb9e06f79140ff61da860f3d4a749831acb7ed751571fccae6e51990038621e6b2d94799b0508ac433ecd0ffac6d5166ac6348b87f97a2193dff9fe00f9208bb0e2cae15593e3670bd52b0d9f90ce8674516894f33045b9d06ca1a60030f4439399b0cb992303ed31afd90b882cb4638f6acf4baa7ec491406d0747009f3f7ba24bdd4948ab3e600e114451c4d5e370b3147811a58f34a74a4cc46700a5771f7c71848478f8e75ca34517268d2c229ef39263ced5001ef4f8ce455f00a5b9a9559667b0de52621b161aaac0135f6e8e2502fe9ca25c3336b04bdeb100427572de796edfbb183b0d0007134080644f5507ee56f6ea6adcfea753c08d0030f82b5ddaae6fee630bb652810fa3ab12dc5f4ba2176c44f69ff2abb65e5a006d7ed3a8d6a15c2077a811a1e0ef6f63e87d2b60eed58171c4bd89067a004f00b5848a1cfc07b79387082647f5101d11a4f20fbac814e4d0fc1a0f69649f6b008962a729e302d48a64f4c37dfa463d7724d82d13fd3638d2cf95c50b9fc87e0001877918c5e41be2a1b1628bf6929550d49bb62e079faf3a4a7243a5ae592400a1ff4bbdf130c5fa91d183d2f23106aab4ff5e2555caf755f99caf84fed70f006ab58db2be3f77ff5b71c5787ad0f0fc0eae1bc4a89f3ae62ccd6332b6ab0700b553e96d5a1b72d523d36636398b1ee87fa7919d3b0896db64614aebf195180004f9770b61a4faf2a86df8d8009b507b1b2ab9a6d8f8648d4b67073d1f065600b74e91513d61711df68d82ec4fb5b86ff25e31b77957b14139cb9eab31fd7d0098639941daab3a8e3809440849158e4e78b5a91c833bab0256f4426cb11a5500a266a17eacb0b7dc050dd06e45591ca8195e8bbd35a83e21b90c943bd0997b00fae84d6fb3df93c4043be7e7294c3fc6aa6975dc08ff9aa005f0cfb60b97a200d4887ab8079d3db4ff647d688f3930ae858e65b11e54eb0d8c5d0f4947122100c8efb22950fb671a8999ca4f1c53a8a7d5adb5b5bf961a0182cc871eeb7de200f72f773fd7f186f99055c18192a162c7749bb60aeae595147e0e562949e3b20046ac74aee4fdf0a3463e84c99aeabeb2ce4d8f3ba1ec1aa6f03c6d2242640100dbc73016695e980825ae1616f2f2de83a683f2d04d3a22ba14bb2fe0780683006ee4a6ea7c2f4b79a4b4434a0e9e8760ba75a5a02f2b36b67c57596a9abb190061b2bb4c440d049078c5fa28c182abee42b7d4ea04cf4fe50a4f4e7e6087d50067b0c08a4fb59618a95fae1ceb496db4edd651dba3b15dd2bc8c8ed962ab1500d5f721ca19010cdecf1ba0dc53ebd4ba2685494d0d6a1917031c8177591b6400ba7774bb465b133e7312e711e6b932650c3504d106896de1c64a2b59781f9d006d8115f0c96b7c8e68df053d620ad71bfc8cd7e6fddeae0250f6ced9c0294800a1a8ea55cf991cda5afdd4c109169c7b9d9d90397303b036c8538b86cf3f7900ba70f67c5fdfd5ac436a7c2dc14909c366f940c208652ff2c583b2b0ad79aa007195404f1e4f77213a96e5e46ea75541527233bc6f7fc998eeca5fe5d0b165006163eb776cb205635538cbc09593b921233e50cbc8bec81b117078540eca34004f3510df20536c19fb59d54f3970997fa7e303af0130234ce3604ac9e8fda5002e3dec038083731f3a88dbf8a146106719d166d6b836ae3a03050b1c6be6b500871d53e6560175c72c76018b31bdff1198539b3c79908a283a519298718f880042e0c04e2969704b33249d50f1d3c6f4fc26c93de32115847398b836d62e4f001f3ce620c1ed4c1ceb33c5a15818286b2ba73aa79841051e0bdd6b96bc0c550017bd20e36287209fed5516e4fba09cf65ea8c089184deb61ea4727304d8bba00c5e91839f84a526cd1775e1c266a5cb566a0c2b045b772f63c8a3e701870c0008558f92c0ea2c727845bebeaa3860d523f720f90faeaa7e38036e168c1186300e310eb5d2733e1119f8f6dfce9b3bde0e1b8df3c12547f1f91654eee3b858e003f537536d9f7d9f24f64f03bc9e540ca9f5cbb9baff75556ae92c59deaff9700c8dc91f0684301cf94f0f83c4b8295b37c13eb2cc64c16c0fcfd3b7c6cf8a10040744aa01e368053eb865b03ec44fc58b82bb87785223e12706ae991e9763600da1cc0e4fc72f3c6f5b0fdff49ab03dca042ac569624c204c0d9f413a0803e00c9a124cccf8a962fe32944c6cc20575179d5e6b831b2721d15bd4d2c1702d5001dd8e678c1f2ee237e21f3e865228def7b734ec4948ef3e64b8ba253b542ad0095a56af45da7a34664a80313ea23a00c41637fe13bdefdd5c585376088ab39003f063e3968ec031434600b5555f01485fa3f6cc19b5f941d3c636501b2cd3f0049ee9f81ebdd305cbdbd013046b20cf78e390a3a763fabaa2fd600a8316277005023a623b21a34c20c9f7f56ec750d081da000d84c1d3e34d4c328c460d1e7007ed619e12b273cc74399b42077572a24050fc709f26320c2a4c334ea12e13d00246a785419ba494d8673cee29c8555f1ddf9f3322317eecaab0f6a755c4a9900e24164eea6c4f04db10f10a1fa916ecb17adce028a9c53fdfe1ae6100b0b74008ca0f4dae75e0caf81c654340842087881f411848e0274be5c968e807a5b1d00684321360f513207e546afa6c715745a867271d9df8b2f373afeb6b4240227008bbdaec25f04a2c78b30a6ecfee82659a9b513d2b0feaa5cd08c02d30af7c300c08542500bda3f7e5dbc0455ed38f7c193fbc731457712e49457b7268ba7e30083f2a75eb17e98b2812b685f729729fa372b4b8dfbf368856d341863fb58c700c6238c75bfe0eba724197231056442d86aedfed57f21068d1ed09258441b5b009428005f75da8ebd26a507cd989970f4ec9ee674691f9113e089b875a0620e00c1d6b6af36e8765d577f749ed71528be2689f0d69c02f58dd2727c06da87550018ff799ae83f6037a15d81bf8131351c6fe2a041b1108e605a0db7bf1f1b1c007f086455d9f56e93c7fffbb2a46bc24eef8315755dea887a79172a702c6ba300cbcd72734f3ae18ca4257a4adf81d8ae95ebf707c415ffd75f76582af5f46400ff411d2091a64d4cf89a57f78ede1e4942abf27b65ccfcf59707aaf59f574d003ff205d324e75ac55a6d39ed1f6033eee04a745697532f0903759901619401005d7467d3a65c1d16eacf2701af324b2b9223befd73d6f8c259cf4e3fb75554000cb3a7a87d21349aa2793efeb18d717adee6c9f6c3910fce5b86ac932d3c1d00adf57e3c29204679d386045082e025b58585caf472105b3cafed3241abfab300614e5b7da77da0a40cbadd26f084ab3773b6eb383fdc05766f3606e4ed6f6a006be5b61e33c11be825eec691867df18f93de0e8eda937a930bd7b0c0d9bf18001ffbfdce490a59643b0c1c1e1592249242d22c285b524d1eed7c9fcff86610001fb35a149aac6945e9b7b1c43025b0e0591f27e0684f095b1644650a05b8490078c958b71a306ad3de9558de067cc939543be90546f80815accbf4da834074006c8a8a43769b0fe32b62a00273c65a43f7b5ee62f85e53526688dfcc20398c003beb7a601fe0f42d29a96f840186f8af0fae64948b45d793ee93c56366669d00059979eee01977be0fbc9f91b97df602d73d19be5fc2fdcc59febb5ecbcb150038245f850a4bef8d4b490abb6946ed7af15652b867ea531d905bb0a8952f8a0098fd71590e21c638b18cd09e0a9b232a037761cfd64c36db76f49ef6398e6f000fba00ecdea10007576645aa4fba87f3b77b09b5a4dbd4800c8f3fef5e90bd00f5e68489fead70fbae59a5a430cbd7c3b0abbdb86c77a9b4c494166d4932bc00a79aead746940dcf9f321821532c9233c1f169b9940980c6fc908aca306cc100a3c0549c1ed2f42b271f2fb894ea3fb57562a487b5413b8febe1efde4a775600b2186bbc3054786d58fb64696cfada9054d114bc94c1d0b439d262c4a5fc2f002b652a3310aca0d41062528687fe4c88c6e798a2e47a7be1d3d3738a31cce300d145f7042fab7b6673baf08f70fa22202d6cbcbe4607b7ce224442f6066a590048c8002e91896184c8054cd982178540c4a360c274a89392c5b7939d9933d600d0b03701a132c4424eb2227baf8d7ce0a0ca13cddbf9c27e4960a1f17babd700cc14280c9ebf8c4e649cb6e8f2b652942e8468ea25961f000044f7bf988cfd00b458eabdc8b6d15438647332d396de5c62ea8accaee1fca46e419a03f09f1c004f2be8b274f2a0be2a6467105d2a935498fdfd698becea63cc7b94fea42b8e00c852439f12e24fd9f0aa3168f04169e3a95d19ffc1904593eb59625ada68e800befe0fd28a753781afa6abaccc4ad36c13f05395acbcb6234e9ea4fec2bf7b00474b3b90de98926e42cb5de9e8e2d0ebfd4846625895cdc7dcd42cb3c85ffb00e00d834b018c0f8e67fd28f470584682df1b381e31e5ac4f146366905b8a9c00346064410e6cd3f9521763ab7f2710adb9caf53631225e6fc62a6b89a5684100e54d97db2cdf2182d5198d3dfa418d1f59ab5dbb35e531be8e1f8e42d3a13e00a155dbfc366d965e4be279246f3d5e10b3f8279b3e47ceb221a6d0d2957f5100e2561fe9f4fcb145e914271cb062c19021d07240b33d7865959460a1ab9aec009fb518e5069797a1b1a093fbfeea8aece20ccf7eb002c6fc597aba208f94f20058d782cc8b33d9ee5cb98f22c4fb30fad29277f7beec994941ced4c5f2db020073aba53046858f0d4859ca4830f8c7a0edf9518200ccf545e1ecd196352939007d47ddfa33002640435050c9138833b2d20907bd1fffc5884d25b33b0375b100922389b8ebdd8beae0bbb07312eac66d85f1685008ed63c2620da2e6dfe938002c66f06a29ad1abffef4669fbcfcbe32bd14849ee7145d4ddd053d36dc2fea0013427498e011d38f0e0a9667823933c2999eaffa3be71ff035da291da2e5170018f7865c462e2f8ff21a3352a54000c32dfbd234ce9218415c9543581fa1540038b04898fe3470f55d27df9bd83cf2d80868eb9935bc18b96f1215b46d7e3700146c771fead627598d2032be3ec98f34e3b4f5ef45305a041a6ef17afdadd3004d8988532fcfa228fcec966fe95b22ed948ec216b65160095e9808786a5fd6000e8ff349e1c42136d4506d9173d843258bdea44b577e1964510193203873710010adff53ac900d8c37a2828f9c3c6966e03ee16999f65ca7ee5c3d42871cf2005e3a1abfa315da5dc0e90773742daf41b5d5f217fd994d8545a6ab926554c50015e55e366b74c77cc0db7260def4b484ebc854841b65bfa4dc2e39e42988cf0080ee5d2aa21c6673ec03d97a61ccae49aea2c213bab7dcc6ad791e864901d600b676606c74a4b9db9a43e4d9e233b08134622459523ee1f1a3a535fa2db7a2008a356c77ff003bc60b9235341554d026936900e70a1f06c1bc16e578e6cd0d000114162f8b863a3c0a36af23f22d96bb58b494cc4d9f595a54f834d8984ff80036de40ad13e557b896e3ea4d4e00299fa09f8ffae365a51f08ac6ab7654474007f6400dc597c08e39e3a438e06ab4d3edf0ede4db79eb94187b2aa4b56f6840055332e860d32b488459757d4adcfb54325fbc77322b3bd78bd49ac5b2f07e300651a384266038f6619dc675720b089a7e850b67b7e6166e0740d47f98df32f00a3233a9eaf45f9a73557a61d98e70a6006bdfaa8de964a9d64d3aeb4e15872002f820b7068fc4322dab909a767932a037577da8bdbf399ebcfc14e947f3ad60062f47cabe9819f882ebd98f59a1d2a6ad588a77fe29b86627767f67fae1f2b00705949a833eb269d3749467ab16b62ca2d857b7b0df7037175a0c8914293da0056da8daabab34af43021f3a4f617522662192884d801657ce54c2ab4e7575c001d9d6479a5fb4f9c5eb5666b2ff4e70d8fe58a89c9b4dcb4643c0808c492b60010769209f61a4a485e7b578b29fdb00b2397c59ae66d2e785ade101d93843300af62d0dcf6b9e67eb82fee9422a801d74239a4a5a5f21a2c9faf17cf72d1fb00400df70c0e2c862fdc423b04a69067e29a37009ec435f54e98e57585d33b5800fe0dfad492bf320de3c04cb18393acc88246dd8020491b4d0803877ecfc6280075eb8902213c6a3134e49a795cd25ea2d2e347f1e85865aaffce2450eeb18e0078e850cd082f095354f3636a768b01a2bc0b3986a5da9b388db2d02fd90a5300838630f9d189e891e8b51f5586fb44ddfb2c5602d02461e784652e226f10e200b1c38f277cc62fa628e897b1480690a1f55fd88490adbec85e46e57b66977a0083093c0d22e611df004801ce59eb55fad8e3c3c9c44ea33a07346f77ca68cb009987e1fe9f6751dce2877cee17deea48a9109128996e4e2c51c015160bce5e009093ceee84772d60e1ef171a8e50d247f03c003140e267294d8a63f772219900a7bd565a8f1eab24a2145910c2e5836a7af7ac2728b14fa74f9f47dc7f2f60003a8e8b00d49990c92f60760c20ac3db98e424a2045474c2c623fbc7342b9a2009e33a662866411944e989d03f1046ead53ad4d2abcd51f6c2b9713ed9460b2004830dae5347f921a0c6cc44e5a0f575777fae66beeadb714582fad7b6e54600064536da4eee006100ff1a8172ae4ff9f4476159b29dc28e2986fe8c7596fd0003eb99ed678b4befdf1444385e855dd09ff436ac36e94b62f965df4537195a600d7402862e182c0d2c26663583c1a6789825a9e9114e7a4e63b1dd46a2f8db20092a472aae0793067ea3b94440d5a45b6b6270f50f41cfa5ed6e4487d13656000204410f477d8e48e229749c66969719b35adbfe2db2c93ef4d01eb22b113f300ec32b79b03c0870c6b13aaaefb825fb4d691b21e10ad013e3fedd31a9f37c500c3aa4c07e18d2b4a0b90a76b606197d5bca564965eb0afae24b0b363e9693f00f425e9011fae4b2f00f013f5866585062eebb29a0c6cb6d80bcbfcad840b250018c7936a2556c3192ee296e8beb4c665a835cb9faea8512e3edb4826ba6632005c6ca3f7d24fb576f80e75da7ae8f9ceacbdbe99c5fe1e2dc36379ee58bb8100d98147a1a3300cce0383a9231124fb117d7c8216e08938889b74acecce8ace0090ba9308264cabc8f6d3348258baa8e4186e3fd65fbf1657a8bf44b861ceb800416aa8c07150a8d8f735b5c8122bf6d27ccb3e8b96f33dd525f39b3254f2410099cc006fe3c51b2b85543789b73a8e806b544a58c25996708fce96c7526af800b4c257e8ce2f93967d10512b09e5e320056a8ab8a981dc1fde4685090a7312004dd30c94c20a46a7077ef4f148b4a103a09b9ddc17448cbe09d11eed175a11005d888533e6fef7f48b4a36de65a7cbc5f8f8de7f6a51d0830e46f02ac6d3910050055f29629a677b72516fe016b12a87f556cc35096e0aca9b42a1117d3384003edd08a0fa18e2aaf382d6204b86203060029ecef3806ab636fac718eb6b5800d8eef5dcec896d6fdba7ea8dc69ac2cbdddd35d957d3e57b1d560577bb0e9f00ca6851ff7a5f1a28b13e01e20f7d675370e73ddeb018d3da873d106c888d0800b661005f283223c9c4f5a0b57634294a1420852a64593531ca280988fb4c5a002820cf31b810c449d83e60aa0b090f14b143d63096aa28bae472c48ba3539b00b21a33385791127e22fcffe3af4ad7553ec0889b8cd3994087a7e07ff82e1b00778559b25bf37b762f0a3a8fa3f391b8303f18996d779d0c71a65105648ba200496e503a3f97f740b680dd4f1aedda721637e0c77a7c5ededb090ea57bb4c000d7c4c95a666f7e9958279c743c6613cc48ea887503807eebb5348ce34a81830030edf57c2de75cd6ba9f55911e8afbbaba0ba5dde979bcd37405b4cc23c3cb008dae233d0143d08515fe73b45d0eb9f73738041e02a9abcfd02e0750f988f800d3eeb93e6a55bd51a331a50fa383ae0c364fa5ea8edb1e3e9e5dbb1f688bfb00740345f892cde042645ce4f0b74ae0c758d21201a65bfc9b44ad69279e345f00cc5496876eb9a36298a7fa29ed013dbe2de6fd90721519b76d2cc026d5e9100092e05e4b3015b3afd43fd6fc6405971ceeb410e045e099dbd2e1125594b69d00e0b72f3c3cdaadf754a3629eb1688acbf75149bfb5f3a2c07c9b15ed4b00ac00a729e9926c32dbcc9d7a195b3b85ea29bcaaf5323a90c0ea079b9c75eac63b0088d2feefb799f6074cc1d94a44f19c9c6211c92a30861ffb585c2b424bb552009a9debe758430b03112c8a89a52b4beba7574907749d6438cc150cddf40819002acad4fc3897d2a741ab646a273b7fb20630f1880da73ee433206985c0529e00d95bfb98b0a962f8caa922a7bad9ff5eed55b772c4cc8b8bd4a5b02d37bd01002e4fb5ce82ef5f8814eacdaddd64cf93c3461dfd56ebb4cdb933b15697a3d800f0bb21471ab3fe94523e659a268f5ef3fdc514f75b44346471e1755f299b5a00d50efc74fa02e22b17ba23113dea1d216f30c3b435a7fe57de123966b538ac00fec268eb51fc540269a0c728da8498df8881837ed0388668cbdcf76464e4f400c78ab1e9afce2c73e4ade1f56b8aa4766f56cc06f969f77c74567382a6a60b00abd1f9c350bb9eec70c54a5c17e82ba74edbab7e69e45229d6781ddc5dcd080006a67ca403bbc4bd4af85f39e6566929f47448be9619c4f6c93d90d090a6b000af09053ad9fc613165df007a23d14e60fcbf1d49b3229c7b7aee5e19a9982d00830e10b7deb7a0ff1f6212379ecb64da916dcf8092afec4b1aa5489e5e0ed9005c3988e38b343a079688ade4f01a6e3709ebb5d54be35c77cb228361caadcc00f832239a11d6bd26c1f288c982607385d662680d3791a342a07bcbc79519b90010d76c450cbb8637a867e08616f3735941ea54db91fed2efc12ad2fef2eac200cef14ae515b273dc03cb54e946c6c0b4daebc1a7648f433bcafdaceaca674e0018dbbcf4eff8584976bd66d17095633a999c3227264a48f8311dd135b44125000b1766938e33090fdf74b6b7a2d1538ebba7b59c9a94d7600e94a81c3f0ade0003d7592d40459049a10bf3add523f497bbf45be4315ee6781f411addb7d7ce008dd327d75cb9c807b7cb2db5f65805211d6ae7cd6ce804d2e193f21b203fde005ff9b0c04d99331ad4011767dcb24d8fa4ccf5d6f9490a80eea960d304ce5b00b3ceeaa7e9e3dcb10f43b1466d5ba0d51497e58db80ce686440325e86aac78009dfa9439ff25a3b5db6df0a2512a1fb2361197047eac10ab109a7671deafa900b234a1a785ca6c594d9b4d72dba2ffa8209ac68cdfbfb817878a53353a84fd00023dd0f45dbcb1eeb00ed4b6d6d6b17dec6293a95b828dec7adc36bf2bc58f00531f5aa8637d4dd48891c26be6328564b168812c359e7e32d57f58cb1127670041002f83748e84d02f7e727db8d52e84e8169763df58ffd5cffab2b63ad32600d568c6e9a768576b11dc3c67b499d873c85eb3556d37672b71b4b73f644fe40093bd4c478fca662f8da97f24a665c61fe0a6df03d87f3112e5df41c92a12a70014bba62c7f149cf85a155d9d3622d9df6390955917f853e45587866550168a00c73c9a02c304ee202f43a9506b6022d962032da15d10c580422d90acee01c300014b01d2a9c1be000b514ec3714bfeb8538c780bae79078b492373a5a7df3a0069acde0902cb62d3df200124e02690005dc9a7c265131b745517885eae2bce00210d293a98d2ef78e28dae286de1c122bc5975b48f25121bfb2e4ddfe0af7500a23de22c8224fbfafd848c296b334d8ee1716aebfdf49010d26484ace0c8c300a98f398c52c5534e12fd848fd4766e092c05cd622f7e2c117a1d9a1dd26b23004505a74a9e10b4c5ed3ea446a72d38d0c056256a06c3b7b1bdaa6b6251114a00a522cb77223b1164248aa9aeb3025635110e235f295e6a07892a0670b0ac29005b3264b6b4b3c40134efc3029e0111ee5fd18bf57845a5fc56509fe1fc4af10091490bb411df0ac0a2a29f668837922186ae25333e19cd727f6e26ac2df55400fdb98c5c88ccb4087b80d5dcc549287a586c5377cdfbafb0af664704432ea300d547093a4ffd6734a975927ccc2112de10f726aac520648d329c518db962cc00e6c421aa98e9bda17426c3e0cf393e94453c24f116896e796ee12d1831e89e00afc13f389bbe973cd6afd89c0a273ce9cb1cd42451058238a0be901d8e5c6e00aa3078d2acd8f415805ec3e255f267b4497efa2c44666ce356c5ca92e0fd8b00a303d22695dfad4b317035e422ffc13417dadfaf705d223f6b5ab9db1e9a570012a33cd6034922919a610e74fe77987a54916b7636a88e9ae1c526fb311406007e39e8e80c4852d6ace887d8d50ab2c05294810099d9e226043b76a87d70030058eb5f0dc71cbe97a595cd421e8ab5b692d650cc326c3baffddae103cc079f004cd317b9f72194a32897e9432c9ec033bdc65941e80cc6e09e00a38385f98c003a7d50848123c3949ee2d5f40a46782e7ad7a75d13a1d4a5e27fe662a8d3ff0062e5081910a2d4cf072af0dfdf52fa0579a6bbc26fd28a0de8e47e1d9d4d2100331d863cf432ab4d6d36c0f600b3678da4e268b2de8fd1e32b3032fd6ad3ff007f67d3737aabca35cd7d2788875ef6629e93beb8a1b81c09cf9f577995bdc3002b87be403289547198ceb7fb8632333bc7fbb3d99b53ed12d60e61da0ace0d00b1e07baed8011647afcbe4e59dba43305f354c433f8532d23a9d09053a018700382a06949bf02c34cd8451b8e45d32cbd224f14247fc7c89f4478fe7ae9a17004dc04efb0240e59dbb2f0db7ec0d4f19b8007c0ca2b9bdb52a5eec80e6221900643c6d97fa1832517c010da8257ca8423edeb3ff5f56dd2106f0eff8abe889001911a726c036ca14ad16f100d0e72975fa90f9ac01aeb255da537d14fed9260007b7aaac1b198db09a6578fab814e4247f97b8cf7cb7421c8790de8f6a98df0086cb3f3e47892bfa67e5fb03b9f42ca0d211a264fb924a5ea7d88d5ac4da58006472661aefb1ba4b7ef6bb5e3924ae3463ce5aad4c16a7f9221ddf13ff476400cd3ff85f8c6cca0cc8ed415c38c6f439f59dc084bdb52eae8a6d32666e7c9700d9fd374d1e3fbf5e9648f92b4001bd8287e52c73e3d3d820a4e3838b33b6bb000263db7a24e69ddb215e658bd54f402c772764a5cf7215267a3074f5abc1ff0008aa8f87b5f70dd6744d8bbe62b9afb1aedd8251f5caba8e2b4e20bd1086c300c13c12c89e5ee6fc0e52dd54b7b91f87a57281804714259bdcecd1eb00d188006a252644618f851629c29a9d8fea99244bf45e0a8e39aebe0e39cd448e61e0000346e41f050d926e8391a13e5793b607ab9202945658c98592a2b34d3c85bb004c22df6c6d0c2aba08c92c402a60ee71188d9d0e15c7fccab97865c79da89b00299cab6c21a42cafa11132dd0dc1da658957d849282aa5535c829cc920ed0a001aa3b13de582fb7c0244c7b538a878b739929111ebfbfaec3ea6ffb8ab4d82003b5eb0f21f003b59fe87699e336ba3aa3a961156038e151c99633384ddc26d0070c11cebc7502ec6b5940ed18cf8114ae19f32b23baa953d6df7bc834ddab400a8620da25ff58afe72a5c2e4813bf157a6c468a474d82c3974b4a9d2791b9f006f5d670d9a92fcc8e9a6ac71abb5c317b8dd6ee976979fc8f81cb29bbcdc2d00bc17ee61c1ee7bec2ea44613c32d3f84beed43f0802f7315549024c1bef55b0003f504af94e78c9f6b77875c27882141077c29ad6664ef5fdaf38566687253005128c521961e3174c8c5c7769b4f3967e1c3001f90aba6f885ed7793c194bc00a948063262f89ad0f2661c84944319f975b22c90e0198dda4a5cd5c286cbe100dda59d1144a82f0aaaace6b95c41a99c5bafcb4bedf2b299b5dc65eaca422b008d348c9565a22ff02f407be70f633eed10817bfb7c9dd833ac8a13e7534f1600b01c42bd07a2e516107765e2b81492d0a624b5e878038fee611e0996a7f11b00bb13aac5741acbbf832c56c554a01a3abc91f1d0b026f8b7f083073625ee9d0026cec140c69ba9ba473ad8fa172c5961b4ade1ba1871533f66d1396d9e8f340011000b92417cf865e6d22b4668e2578572c02968cbac0364fcee4a9a8eb3e400ee813d2e165632a1883da00bb9d2846128555d9e80a3b15b92a58b26ab1d4900f51e8ce25e6e7e284fb184b2166d66c18242207bb7ec54dfeb383137b0ecb1006023bce024269e1663d78ad1f09c5bc2ab781392efff1b3f6cb8d9a114faf400734def1a7e33713864437274ff8de4e01b20f721d4adb9ef706c94d99ece7800a71b80ab0acc1e20928f88a267d17ee1a543ca6d231e430bec3d210d74a3f50075e26cc61ddff1ff5eeccd1f55c395ddd44e9a7b7f723f50a3fee307e0b2d80039c4cd1de61d3b0c389e84e6aa4aaa84df5893d2a8c3ef1588d348bc8e496f0090fbe415740dd433604fd1aa987b844f5aea42176e53fffe73550881515c0100211ae1a118bd36e23914649ed7fd328885f604f805dd40619d75c732a40adb00d21de700b461be7b39782dd191655036ac4689f4048a03a8720c4117c4abee00f54eef34f878ffe40ff2e6bb048a8b1346c927924e97f646ae171a37aa587e00b6020d1d885106608acfb58542a236027fc7f91a083492e4e5cb89c790a19800dd4a6d8ff1688ac8d902391ea2953adead661c992520bed5b183876733b48900aa2c6e0dbfb8584700336f3de683eab8c4640fa9d386bc89d96b001aad97c4003391190fe5e4439ffb67fd2a01e69c344921b39b9c0bb395a0d947773c3e240019e36bd7dfa94bcf0cca573e46a6c390ae0c8605254ce0cbdf1e166e4efcf00090f5fb154f4034e049ab6953f1193823b187325578176140ddff668b4c302a00e352e531bb312f5887b3b107c6f349da5257fb13e9756383eeae03c78521df00d29e098af9af5dc39712fae5083da74766c8a1c5033d6aac73c0a2b7c27d24005cb637e31db19061450f177c6be56cbff279d30922623f4ecbde7a4c5fbfc5004c90d0e404a11ca8d44b3dade714dc4b3403166f4edcb6f9ee62ffceca7365007e1651ab2a2d2e186226443c9356412c619a193c27f37ea15474631bc5682d00db049a18bbd520771ceb98198d042d9aa21e11ea40ffb20ad451f6b79a233f00bf3e3139e99d6904e140e4bb1ac2261941ec429708c19c74f0cd8f695b289e00b6f891d18863af842619386af8b4e7367789cbbfb2386a1a1b116edde009390042d1cba425925195f525f27521bebd33502629d6569e6ef25bbf600c5ca80800ed926e07ea38b328eb3bcad1a16bae7dca4e920278fe4a1d4c27acb95bdfd600d48aca6a325e9498f3961ab3cf153520af8df3d7125b384268cfc67ecc3d4100fdd3bd6bcae20af4e4b76bff0ee94a6bbdaaacea163422647e8424b0ac5ee9007b8138bc319b70dedb5c0109dd1eed5e0ebecacada38035adb835b5738981400816a75aafc26f8348a961df2a47e980de4319b6656032a54e05fedf4c873cb0025499383c1b301de62a7a2902c581423ee55d499021dfe0b0b6352746ba849004defe17f3d646d6820635f77a7412c6067a5d8f9dbe3b0c150abde19b8afe30019eb68b223f0c61a09b455a31340dcf8708e1ac252c60137e596e82a9faa1900225a1f1ebd777739bd1ff3012a2464ff0e0da53ac3713b7c856800380782a100c9f77e902b3fdfc77a157350b38170e61575b62eb932424fc709826b1fd0a000ea086e79a73e9c734e76ba10b171b26dc62e7fa814fa0223855ed520e155e50074fa1739c328d13be8e8f3c4c030b0d4b72aa014dcd9704c4ff1afd5b842fc00d750056e2ba757c2512c14a33a45ae7997c52fada88355ae4b67285e66205c0007d064764835cbffb5f13d2742bce3ee3cc4f22b9df759efec563c43de543600019e6365ae9e46a8860624831777fb8867eed94101a4296d90a30868fbb4cc00b1394c2a8a3fa84c32ac89013cbe13564f24923a2e4fde4fe26fa2366dcb9100e6cff03c26afd4351079e7e750a8fdc55dbd2b7fd286975db67232eaf8e4150025ea543796b92b7c4ec6f68ca34ca60d926eaaff51fed8e033d59e9adb703b000070ffffcc64b102e3e1f198be3be5070c246498aaa474908a8c013b55f830001064ab5aa865e899847c680bcc1096e06167430dda94e521909d80988b5ca300d331add584ca7f81b70ac555f9956bedec01508b36e04e5f59a27e8a74238b00be59e449dc455d881e26143a1368138d879be7bfcc90cadcadc85d4ec24c2e003ef7014202be335228673437df6bb6bb85fa4ebf7fd4a2f2f5e52ea3d509aa006a0117554316927c7901ac7258b42b947c2054d09dd05f21cf80d5e75036e100fc5a9293a2329b974aeed1765473cec80f7189b1d2b9ab0471e7f5bd0dc2f40086c7e8114946bfcd18c456a8e47ff510cdacc63c63f0267e4d6b7ce37122250046c7c27ebf051915f3f2e653b6b02fbd79abfed9d642dfb71c2e6c1dfe009700b37f9310eb605c7b6839dd1741d1fa09fd244e898a6305c5a77882924a35a700ab2319d811898e14daf6423c92614c79f6dc27a08ff4cae2f308d969a5b1260059dbf00987a2b60c802396ae4a7791c57d2f9e9b8c6431477a0bc8da56c6a0008ff292733f8b9cca01be08fd2a6bb8e144c9d60fa0a4464361570fd49a8b8200bbe7c3d5fbb3de66eff7508e0af2623809a7a06ff2aaec3ad6db2d97ed35d40027f262ebafdeed2dc82f896643fb31dfd60c4fcd093c4d9fe580d1af8fd8660082c089711d5b0e10e612f1ef841104fc450749d26f09a5658e02f64a6a137d00dcaa4305f3d5e953d39c32fda53061b49637d014c0e8dd86c280468660bca600a9c74bc3cd04fcc6222cfb878a5f6e4dc5b7c75d337a7612970d14ecc7fdb5005bcd317ef82bb1407c0f60a1a5151e40f239c9969453db3b5e9e30d884577a00ed49acda47d76759b849af2a2c6344177cc71614808ab38cadde35f8f803d30020688d421c04fdcd163e40161a3a41b76650e9360e297bb8460165feeb907f00ee44495621f118e5217c0125520f34e0cd20fa9355aca42a19860a974e741a009688eeb0e5ada477cc18ea883874c501cdf151b281bb8daf7f703d5246a20b00946e3b796f90782e66c72ab2b8eb2d093498a3817b1cba149a664ea28494db00bf13b41fe74cfa01850775300c749eff600311ad8f82be010ee560b388febc00879e381839eab6077bcec20c584accbfa8883f28de0af52f768d1d37f51fae00949865dbf2b636b60715081016afb410c5d4e981c542a79ae0e852877f2e63008062f5feb28d5bdeabe24f8839f57ef74ee91cea189e032727cd70beed81b100db3f6eb4d5eb2ac04be27b23a302cb9f4c1493cc43d5bac58a19dd5a45ab9d007ddbe10288c4a145c595c97334052614a99e71dfad113584e40e7ab4435a7a00838b341b4603541320a29452c877286cc06d1ffa73adc68064fe326dad0beb0051b8bde4253e19047a4187d34c8941420d4cd449fd599f7009a13cb4119f15004b4c2d1c3155438147a519241ab7d8ec089b13b8af95b94456667567a8626400cb135c271c79ecb6658945afa0e1bd9fee7feb0b02d7a95584304aa086add00098d72d480cd6e7476f394e083e0a4f05d865af66e27cefe56ad168f08fad2f007a05d1902cbf14a465e0c577f80995f4246dbf28acccd296b8ed7dd00a5f6700ce793d1f78e29bb9f2b990bf422cd48421f5185c5bb18f62a81621b0a17ebc006757a27cf4bc590dfd36b0c79a3b23b09570e2ea57162d01f5b7df9d2c34f300249b76b56d86e09b905329b90b53ff3a8dc2881e37b61782cf168498bf20f60044f2b716b36b1619100bc8c18bc272cce3408e7d4022f9b49ecf68086437ca00c4b2428d7936421cf3197f8a15ef0c746272c92b9ab6c5650a2e055ad557fa00f1952da86dfc4ed3f208f71ce85db777b4fcc8e6cc96f17c295d5903a7454700dbf3c7c22d19c079aa76aa5104e04c4f6e7dbd43b57f3f8cd96301179da27e0066fcdd610bab613b6eae1e2319f20f5202a100b3141d6f670faa423551b3d100866d5a621a3314e0fbeb91493606cf43d24b62e45ebc28b67d22c643c80c9a009ccc85f4c979c4bf210d9a66a6e6086155af3c0238ab37a1921a73a36c22540036b33bd636c26f05629c653a8a2359a785df6ee2b42ff996d778ccd5af344b00cd90c82f86a4330e8878628511f41d8619ba7dce82007ddd7987ff5b91354e00f1224424e2933310e12e558179c31e391741ebb55ed1c73ab859bd903d1ebe0032597c8d96e6c9367f1cdd023915cb55b369f0301c1b46d91f26945faba643003fdff742fc75d7409da27ebc1dd8b063ba6c319f5b5d247bd71f2432ca4a42005fa4ef89d9af93ab92748a96e64f739199cca7379f604ca2399728a7be6f8c00c0ec1cdd8483f5b0ef01d78b02927dd7c7132db0acb37775f217f2c5f3fb520001a6afd4e65d1e7ef93738a771cf1912d3c351d9c7ff4249ffef73ee5855ac009d523700586ce6f6f841fb1ce3abbcf9a3c8caac8f6a494c7a050f46c61ad7008ba5537623299fb3a5cc5c48e83fb725c377a282777a3801148559d6b3531a003ee7f0634ad2a91a9ac44d03198e98dbb77eb29277500d8f1fd1371dfaee5000ca8d9e971c6a98ccd88350962f698e8d5e5846515e334f332297768d17651900cd85c06b3bb32cb934f872cdf4c9e67f82d1f5814c8cde8c74169d9292e98300b0bef65683ae923eb29d390aa7369f257aca6e7bc41b430cb48f6a861e55580045350be6b422f148c3adf552c7cfad5216eb23497bbe75da9843d83abbd4b6004defd8845f1d42fda53e60734e4f8368bcc58a4e0b859ac0545b2754d14b6200b145181642ded950acb499d30314522a9dbe4e8f95795912397751c5bc138c000bc00569e5b3dcb27328f4eab4928c845e053d5bb7866c2bcbe7f38b7d3303004990c5a78215c5b20769d41890c14b04d8cf673fc19c620a675d16fc773b0e000a86b7083c893d7e9acac6ffca31884b633346dc9ae23c6d68d51de2c6f1b5000e38aaf622d1df8afa9f4a1f8f93461acf48ac0280ed8f761d09758e73d8ff007e07feceeb6fe0c0c25103f982166e531131ba640cb4d51c1a5442e0429731008a865abe4388f2082ae38a56cf23ffd00c7c6b7f8608d2e6e400ad7dff4edf0061038d5b67bfb04604e01e8fe7a4232cb19256d989edda1253cd7f2127a6350095b4562cbe5dc364dc51a4e8121f8ccb42821618cb9e94d777d71916412144007d9fedd6250a45cbc9d19e72e8124ad66375b4a17a3abab1ff67602910bfa0007c36e432657e7d1a6461fd2a0e319dd0f21f6704328e5ac846b278fc706083002d229f2292a74306e6ced3f7ecfef3bcdca97716a9535ff6aa5de10db8d79500482a1f76ff5f76ff464fc737e08822a102458ef55142b1381b4924c76f8f94002fdc9966cb657937bdf16fba840ac5d70121c98f17ac7d911627345ed8b0c9001cc9a5de77e4e37d1f616b628a480db7636d087dd3a91d84b03817aa75a8a400be52c62a1de3a67f1869697f83e1619c7870e3103edce06fcb5577eab88f3400e003821fe6c9870469b799b5fc3a7fb2770aae5bf801e64d4318982211393a00ccf09b476cb395a3e8b991c960c7720cf8fd8b25116672fcbacb75e30125d90038b022f552f917b632912451fa766c91e867c2e83e5232e050b645c99cee5600a07293ca4951929b643469f7611270a5ade8d39234491f3a73bb45f34dbaa900a294977c8f2fcb2ec6f5b8eb1c44d76291f8793180218730b665610f5d1165002b39675035faf7b05547109944390301b09f5e4852255ac1e4598141c583ef0083ffd343797fb86e475e77a579ce8aad835be5351e04d35746db572de3cbe8003bb7767e62815de4448c991a785c2ec3d0e6d50f33331f7722c004c903c0d700952f13bb777f1afb6ca12a0031d28989d27aa88adb36c5ce7f6c04227fec71001201d8ed370d1ec015a725be05747167b298528df46517ebbfa569acd43bd000c3b26f443c27043ae3bc4109fa22e1d4ff7fc205013f5938080e1dbc7bfa410041d92232174cc7327d3a48230d82df630420dec7a448ae8afcefa3f245bbf80077c488e4f094cdb0a18780c39fd431376d10efaec13e2cff0247a3b9c62a5a004130d945abddf3a00bf787e80c876f216c4f912ed12ee46e477a967e7212fa00dd3ab68a30983ebb066f777e9cf41510740841e88e7e3a5528a416bd18771700ce7e4891c0e63ad45582332d68fc67d675c8d5e3395e991cbd182b7758ffa80046a6fd0114879c281311d0d0e4847770e98b905ab5b1e1a69756d325ab137100bd807ed11bdd72af9fc4153d5b18dbdea8e4b8ed0f8b2a9bc3ade7512a364e00e2929595256e2ce1ea4f2e5bd871057a25902dbdebe5a73688bb8bd55cec9200f02be0af806d871f2259d71d5049a8f9368c491b3daebab92cd084c0d65bfc00ceed48fcb4a2e2593ca0cdcf3083b9a8ca40cbc6628aabd47149d37f2d919f0034162251d8b7420c3116fd85b5802550474fe57d027c3ce18224fd65c1ca670001b963aea16b644b963c56269a0879d7fbbfb399dc46c75adc12dedb2fa912007ae384916f5f3247489028897cd4f57138d6ed2c9944b036f7cc95d63fae7a00547ac84183127daf3b8d479bb3458077094558961707fcd381a2c7bbe54acc00228a7767e40acc0323f9ff3c534a562fdff89766795ec5fed3d8b0b6eacfc000d28cfaae8fa5066770e254e822e461846f04bd09e609dab927235cee4ab44d0022fcac99e53b8fc881c9e8ed7e41c377408d370fabb4c26f82de7c2608caf000fed4bca7e69fb404d2652c4b45329a7c7bab8da4c5e4c8028f04a53ce6775800cc084724c838311d2fa0972c57e0b419d44e4a3d1462dbbf369f4e1b5eaf95008404568ec258ae4d4886d39d55eecc3370944112a6e6fa7676d6d9b1040baa000085c62c829b191915b45c539d35249966e7c8b46538373e38ff7a860696d30025752b4559ce16604eaa2a95d5c33366c0b85abd294438f2c03f6bae2356be00a240ac325161381a218df25477918ff232514e5c057308f199792829de2398002fcc8e8122d3ebca2b64d9fb1e214f561bcd7e56f2fc16e91a8337dfc3360e00ab138c6a53bb30fa4a8e97c30f07a3b558a27a673a2b7741551d847b51c4030089d894cf1ea84b0a3948819578cbeae446cb93cab6e5b1ddf7a67d63dc5e9700bc618a510327af11d57a482fc69f526a3a4d1a47ddf21e2ce3b3c11225989d00164c9c4d2d59f52cfd5672f44ec77bb5d6a9f9b24018301cab853fc798e2a7004256f46df7524b4b67cf27dac450385d4e682e0ab3a80516c868cd94cf2d9f00a7bcf97df4c53b0e1edf9001173f37e6fb08b45d9104c8024b2d30b6cbdeda00673d7df6fb97b4bb02585eaab115f05756f6f0579a3144b9a398f1ac00613d0067d7fa1f53b87313949a5d435c25a39e88969eb84e8cbcfdfb88666d96657200faa30855951cb507cc513b4f67601f656ed579e18a95495b9d1afcb66ac412008fdc472724b09193499a8889bfb761b27c20097e1a0e1095028c3ea2c2151c0032d975a6056d16f702decd003152079a09696829583294aeaf02fa68d14de80007f4c0d590674d546c5f9bf7c66f25da1af0aea2b29477873eea66aecdaf0600c63b136a23ce939a37a269a4175c4e11f090b778c9b45e852e60a55b9e67df000e4aee7971a2b14d5955e923e4790f1cf8b28939a8426650e84e34484f1e07003bbebbbe6d4e6a1ab526cf5df16064571fd2b2129e8e81464fe488f1d2b468006ac5de9492b937d33bc92244b6564a07cfefd4d34342dc24af7e738f8d73f50068e9961a6b07c1272f8cfc398c8ad67825b74e2653feaf61c54f075a6b11ba006dad26c88fa1bfef1f81dd5d4c8484bd294617fdfc9e1ebd584be7b8ad15cd00e496a2f368ef848d5dddb6cf1441f143c253128ed713ff0cffd08afef83b36008cdaf76a46f05164a381a8c51bc6a7349418be07d15042d3158456f77fffe800c536fd1fdaf769a1de33e762a2b9255d1bb4f3a52398e700243dcb27dc5177002d5db19d398fcaf123930df11acf23e2b0061587e3924673b1b5d56b2097f10010bc3fcc2edc12637eafd6089cb7632d05bf6dc6f6a7e20fd58f191c1e57c10086612433efe376b5867c9fdfacd90c47cbadf94989594d8ed992d5f50b50880061bd0da51673efb49d3a2635ece624dd16004d094c1c547aeb3d3c6278dad9009649b184a9fa57498b7c79b8f9a55d58c3dc93084db28e678cb9a68e3d2ac80026b6a6db0669997d3684abe45cb48cdbd2c7e97bac2b87e9b37c65e171bac300179b7fbe103e1c3ed3cd1ded5e4418b206286362b3cfed8ea5201e1db9ab9400bb7ca397d08983024fccc1440a72dc1d5d09b0ac9607db42102826850ef61400bd38ec190bb3a9648c9ea72550f5db92892418b53783bff5bfd673243dc37000a7630d62fa02eca2c7e4309bc83738ed2db24e52d6846a0282902caa99a6fe00e1f0bb61e129a94af80e6b7528a4c6afe9940722a5523c510569a016f02a9b00b56112d15afd09cbac234ed66f7c9999b62906592f820cbd98265ee242729f00ea91a307e89d7580fd9f97ce6d8fa6243a029bc7da37e8cf95c4c8e373482300ae69a56a2aac9d80b0e4965f653d7749a2c61566e898b67058115c31990074005ead126e5b2ec730081d1c80f2a8b61bdeb8b24e8f49990d968313b9daed5c008c4dab36d75ea07c1907ff9feacdea64f98d6fb34d50f25b9adfebfb3d851a0006603d0476de1005e99922398206aeb32326b2b271ee679395fcf1d2144c0e00d4d87adfd918071cd75ef700993ec7b117a57345e664d943e1f1721ca26bff008b6580a163058248ba9b99c46ec319a13c3da3521f575707bb3b057b060c940044005de19a987e33dbed9830f57c12270125de4f3e3c4ad3b63313082d57a30073e51c5b966da26170ffea1188134f097e696be76c2dbbe0be47e77398ba1a00e083f98a1a49a7e3caf4b8a830e46ea674944756ced524b890530c1a45ec00006c640d3e8319d35c6a1cae555ff632c8115196455e086a92a6243c29af4f8200cdc40fcebcb28279eb5c32097de9f403ba30e081610af1283f2b3ed09b3c700000b5e3aeeb87989f9112d7718fb9bf854a2dd842b9225b7d77b368385b501900fa505de3df0e3258a3cc7aed957fedcdf279170c661f9c8d3f64738ee44d0200125a768750d75de216964205937ed4d02a053b1e8f7ee7d52425d6cc119de90030a3c181fcf8f89a668dc2ae3c54a018307aa1b9018df2127e1ef1c97a099100132b836df90988091b9ed111f30868ebdefe08485ab0eb6381ef0c6fef27f300b83cfb483a1f9be2cc04e334ad84a69b8c5acbb260e92ec4d06a9a81681dbf007fe075430e382cd1507e168ccf193c59732d96ea97cd0a5dec3f05e8fcf60e008a4272f7dcf5770a23be5e8b1b6e99a62781e3aa407ee1f938bbb84935d3cc0059e004144b6782df6033a7e7569d655e8b30190a8898406c05f50a3b08caac00f2689461e21eec7abd2b1d319fd2a56eda302002b100d829a61a32b18b916a0033b5738d7556d71523cc9063262dcc50fc82be43f4cf01f308f6c9dfdfc521002e08a9c12bd7d485956f55bc26e6fe30b0235fe94d5d0b981104dae168a976001ec3b9239d9f501f344365852544dd28972f7b513e818239eabe394e81374500e31868c7ffbc8b59c9be5514245bf16ae48d0b85c35661e4cdbad0652c6744002169480fb70a43f77d372d0f769fd13fbedaf1daf662d541bbfe1e2d340fa3007a6dbab35e2a97a33b006f0f854ad9ef46516ae492d2082bb7c46a055ab10b001f29293c9c84f059bb7120ca9a9f5a22cbe4771de3eb31f6ff778a18b62d9800118d8426954499a20aa16a15b370c22bf8f4b290aae2de5b0ce86881b8902100408f53cd4c17756162eda56836a147bd0078f5da4d9d765c94f7d4e6452d2b00bc011b8be1b9e813ef16676040383e30fa079909efb1af708189ca366fcf5c000a940f930e70a1d2c4cef4f2bdf37934393106dbcea5c3fc736b3cb035b2c400699ad40bbcb2d6a8cce103c7c2f404b4f2985ba966cf1a1b31f24e8d97132400fd9ec20165846c499cfd5c8ad947a190d2eb3ca1b589c3a307e588b2cfef4c00bceaa810ad87ba08a50d8218c3634243412de121c1e5a57ee59fd986e61a6900d5ff86604c342561f6585e9d1e3c3e621f02910c173e7d9008842d660c52d800f654c114ddad848af9a6195c1fe2726f33b9dedfd0b82564df48bca9a56cec008e214a76ec820db879727e61315af572253ae678e5ce8832e539050406461b00a2d2792d3afbf59eb82f8094066627694e787fc991013101f3d232f495e36a0035db05450bf368796838e58fcbbfb343244566f039e6ba294df632d2938f680011e660557f630f3be24ec794f81483110903787374d54393b6dc7a0d31214f00146bf53809f0459e4088f8b273dfba48dcd09b64241a38c321ef1f2106928a00fb2c08c42d00d942e22c465a237a41087774a090c2a792d48e907dc24263a400463f5c4c28b4e8d8c02f9a69c938679c6db8734123a1ed865760d8d0fadcbb001f44e2105a0eab08433ef6858ca78db94e938882efcebc6978fbb8c38cb1c200e953ce6b766608587b1e80c1f8bfa41c91cee9c4e0784c93c274cb1461223200f23ac04e9e16f07ce086e92fd1986532eb31957b9dfba0539b121a488506a7000ae0a8adba46e493289eb384dbd2a64cc6ef7348b649e292ac24c8094e572e009d485ac5bf2ef61f3fdab3a884d965930da48e96dfece4bdf658c6628db37300af31783637e938f172bea0ff32d75b22cedf35e15d56d44bf014a0995f5b1e0031b41b82e0874d9e75b7632ef9c9ceba1f2b2dcdc3640a6354402b4dd9cbdc007f47db89a9554d038c26bd8e1e840964d11b30f0d43d7b1ba0f5f16c5ed1f900fe2f0cd4006809115f1092eacd86afc6c8cdf5ddd8a5ff97d4d4f1b08b2481008804afbd5de6931604b0ed2ec2cf74360911d305220a40a843bfc925d3bd01000acec5cd78e8f1d78c08246e0ae12bf566eed2703fc878ebe2b7191a5336d3003dbdf829b036a309235f7a76ebe4ac9151350b2121352cc3a6e3ee26f2e34700c2d0facb9f88ca57e891d4de992026c0e77bc5596912f6779b4eb55b19969c006c4a033b9daf54e2dcfa0a3f36094bf1cbadc3d2e9967da0fcff3187875ae500cf9a548226072d5564c0b3694e7412b6cbd64ecff80b5c05763b022aac3999001041313fe36ac027f8f3256898f5cb82bc18cba9c4c2d778c5760d8bc6ca6000236edf970dd62ece5ae53afe53e9959089f8cdfd753047b2852475f6cd679100d95795c5915515a58631e6e280708c8f8084044da69d8518b45917a88f70bd0013ff042b4dab371760577427aa459fccf4fcfb96726765e9aa225bae50eacf00a327c08fc397030c602cbcaff600f8345398f6e874b1f3a00501817249ce28004e8273393247996c62d0999b598c63eee77e21977ae5e3f77cb501b2071b5100c721f16ef37b175100cd6f01526865d249549c950832c223550e67cd6a45e600b2bea195023b7b3cd2ba5fa8e47bae5365b2de11dd0a29f4ea0f572e73b2d7000c3ccb97ad0d59bbb4c5d3bb5797a23388b74673190b7362a2b1b921cb3dca00bf79af1ad2aab95b733ae9ab2907d8bb63c9c1a54b35fc69bc693bd96c949500e99adb3227b05db578210d31d0365db042305ed9aaab41cf5343eedeae358c0053d6d76723cd3312f5e9c9e4cdebc069b72817f3eb9412c3026d63d92cb8f800c26ee91baa31129cc6ac8d63e885f56b714ef0aeb125ae3a2a90b4f70d0398000241bb9e4e7235812d2f614ac9aed4851d28ab7177738708a7519e7fb6504000e8ad837402820afc8234c2d964e97439f8882e023a58e48dee937cc17befb3004850c093d00a090a5ff0873d964edcd2ebd2766c8457810e1807a21e77a56700a2412278d4b69a522d776c36cdef25634181e08610ce0369988f04dc56cbf100ab43d52852d3558ee0f803873321c60252ecf6ebf6b61d3330f37be36d7f980047a443a129e63bef534b332c54e02170718bcc167b379573095998878881a0005f1343b8605da832a66527ad6a404ee425fdcf9e9aab7af29b514a63d755ea009435b0a59469bae315e4c8dfcbca3bb9cd2f0b0cae53b4b157d3081f3e6d800065abf580233b1ca40d75ae87fc5885210cfbf4e7990a220ca973fa9e04b5950031762c237d22f6b3f4446b3e0c54c9e5d9803f418df15ebda7f467ad3abbed00a2e7886a989eea407dd14b2f175b3fc07536c982fa9234cac7efbace319d1d002d7329164fdb96de3aeb42aeacaa3b836ad7bcf4fb89b1a99ff62af74fe8af00363c802d056897f164fd7f07f304682b1feae32e8fa03624fa899c355b15e800bfde0d0f939c7ebbd58468e4bcc5284fb836c66e8c4eb9b963fc3fa6896d5900d30b14369b8f7bd80abb932770da892b2a6785039d78b092335fc786fdace700da5a5d40463b6100e75564aabf1739fbea735079790c16315094f1c66444a700cbdb50dd9dc0cca358055f0901b614c72d35630a5af82812487bf80d6ae0c40015199e93625c0a330501a6bae57250d0dbcb4959d111de34f006297bb05171002368e75bbb5170c148ae2b2a24a20922c494d93acf79cba3b9d55a6ef4abc700cb8e23721398c33124b0456f88f592c9c8860e3b30bcc608aa71f7ff25c91600d42dbb85d15966be9138178bce6990e28443bda2cc81226a167ecfe7095b3c009c765c11273d17ad473a32cd064f53fed1fef387f72efad3ea35241a28c88000007f5bdecc9db1fcddcd4fe40352ca9a73a520f6561442430f895f5c66cae90019e4eaac378a07dfa71326d740dad9b2ef0264cba9ad52592cdd5e8a1f2993005bf6c16d850f22b7b8409882bae38eb42d060045e70a78dcd3875b3f79184700cc2b82fe6f77a0f600dc63caddd1834792933799b744f73092af12f452da0f007378203ee21ae85e4929f0ba104d045652a6847f8e9d9e330389a5bdac432000976395e7a7bfaa5b37e926560f7c1917dfd4dc95ee92f0971595e6366c339000d63c415a4cce9413260a8bb9b9ec2d3d9b263d07fe2520977dfcc00c19897d0057cb6f9a70cce3378ffb3085de6baf7865c5a15fe1c58096a8ae6ebe3ff6620080f6752524b0e122c5898376ea9d35fe396f0c7514e90decff7c80cd6156d600d1bc0ff9f5b60ac6b4d1d9516de1fef899e76dd5dd04130b2b4f92b5ac84c4003afebc3023c34d3f83bbd28da873d8b917440d306b7ef70c3a3a3326347f660017bc3e2b54b000bf03a675e49038fa7c73df3418c05865bcf2712ff71c754600fa786c1027a896f34f52e684a580e84c32c4a7294616d0be82f02459bea9a500feac53f439c08ba70bd19a2036f8d30ce1b6c8539ed0a946ad4a7e00b2dee800ef1437d34ff9d6f673ac6547cdb0ff6868000c9db88d9cfadb9bf08a610fd200c3535753f4e386b08ca40c1ce45a267731398bfa3a45e82b3fc5af199d7af100a6ae53a5d5abd6ce544ceab8581a069760b75c078a17dbadd07751c7e52eba004b85bea2715a289372648aa18593ae981843b6808b5064acd280403a488baf00e17380bf5f84a31bcaccefc77c1bb582f4f2d84931ad90294595c9cdae294b007a3f79757fbb75ac0e906dab1b2969f7648f2699adf9593b1c93b28901b3c200348ab9a5dca5bf021c0b23246444f10ff429ef7eba21bea22f461e1e2ba43f009d158136a4c097910b92bddf0627b8264baf82b1bd60235299849384f7cff6009a0a60f4854c0d1a9b259ef0fbb04c49cd7fdf8f7adab7274c8c4549d76fe700c72edc26b9ea4a3aba10edf0ebeb20a3a89bde53d46852d5e579ab61ea519c009b12a4cf4edad45c6469bb4ce673b648835db25b6b41240e95f33b4fadcc6b0005e8899b5bd70239d70b196aa8e96339fc43cc2ae33855881a7a2ff71d0a13007a87d1f9dbc28e352267c11f715b5b587f336e74ce95e1cf1a5fb2e0177c7d00409039806811698a154be49a9b8e4bf50a40eba7f2cb52afaadd9e7aa2973200478b5a95efea4c7809835faf761485fbe002f6adaf1d8f5c9042cb133100ea0002582b231860a63e98699fc9230de20d681c3b749182a036f4be51eeb0a9f900b6bc7dbd86f41022b8673efed1b28a910535c163a3b1ac9db99d902813813000b45d6d98f53b921014118d9cd56f070c540a033d5a6eeb542893fa21aa6440009b2c36b89f6cd07f370dc5f86844866cebad695e2a8085302d95c52559aa2300dc438f8be1b171b8725534f4107b4aa35bd768820c77a8461c41ae2c070f6b007f181aef49d3cf843742cb8b4ac7a93247378a76175fc49685e6ae73f6216f004287c4f115409bfba6482de22b157e3353ae3df967afd9a00487fec758b2e600cae811a8348de5e03812d8ec26e1decf39be638e9ef139d87cc3fab388d0a900a8fbc23fc7d3568715acbf7e58a24c7843b9aa1994448226e2c49eece9a24f007846254953564af74ac314e791125e58d693fbb775051cc462d3645f8bb368004690d892fc2464e46a702bd01f2551ee01fdda5fb3609d8889fd897c0cee7c00337ab8a92fe1a4973854d64a02bc8809a3041291b6ccbd144a46b6a06bb36e00450fb8777b499ae7922d44c8aeda75ff1c51d0b644db6b84066fae38b579d5008122dd93dda2f15a1a9d9fe27fa0fd6548bea068096a7ff1b26f72af0dff1000da986e16737f589f7ffece4d192a7a547569c814340589111b0c8ada89e7ea00caa01a137b7db4f92a52738e2c2207f8d844dfb04d46e91d40b5a2cc6315f200c9c0ea7b591200f5cf127a521cb81c24f0b373a7ceb712c82a0c7ee3c440bf0052fd39dfcae8c6111127b7d12c0a0851f265d190bc972254611e59281a7df200f2d679f0cd2dcfd355aa10701f5122d837bacd4802673a3f886a842477d07a00701b5fc14eaebb0157ea68d8e4218a94afb6782a5871f914feaa0c76a8fce400dafe689e0585872c6ee46b077427cd41c455723ed097aee625a6ca6ef3d11200f5fc47a7f687583ebb082cc6e44f1d448cba58b945af35a895185e0f8c5547007be046ca9764658b48c60978ce136697d7ef85bce4596418f9bafa09488c62004a0779bd2d2ec596dd82fc98f016ff807e7da41124038bdeef1e28dfdfc68f003f0d766cda381c8f5bf8ca56f10a2c9e023d74c872ac5cc9a3891db660d23800d56d0f9d301f0f51fbd31d3e4e26bca9919abcb4b1b64d8bf57b1a38e744d200dab4d41aff80645e2711f3582808cda567486edc3967c85d405cc12c60b5fa0029223165825e34b6ccf16e6842c607baf25652215983a3480bb2d562b23f8d00b48b3bcffce03e83817f697f692a0c5aaf44a976b8513ed7583bd5fb17e92a00bab5d4fe6328fe69c087a6c885909c43d637e3a0888b86c40f380a84dfef5c005ab4d848239ea1a578d7c919929fb6a6808757889a1831f560448eaebc681100a0677fed523e0a8c468910fe5112bb0f50b46399484b72c0a2122859e240b300d1aebc17eebafac33ba1ab0d8825d17dd5b90ae948cf59184e60be45c43ea3002617bb2be66fd97a3b31a90b71ecde0ae40e4ceb6ca6c168c5190f5d70ae3e006efa93bce6d0de77b28df279a66d5fb4b5ff80550e26e73787f9e8776f7c4b0048828738053dfdfe9f199042a7d81e5e1508c9fb871cd3621b2f419d4cf2a50011ee01083a59232ae8be259f136d7dfcf3b24215f006e9f43aaf6e26b96cd80091d998e6a8498fdc23a7ba87850cc1cbab56a5380f080e88a825c25e459fdb004fcafae71c066a3aac7f43f8638911286a215f52c777b63c860cd7ae1f8e2400ee7070030461e8de409b94ae59345a22bd195089d0ce753b53bb14c5d5828900f4524706c4aa4e2f114eb730b3a3dfe8c800d316a234f95b21e09ff9849ad1008d2959fb7b3171c476c8e03c72addef4de636a8ee7f91e7f50e5a697e6cbe0005b343dc9885882a2e727516613547319742b76659032f78d99a171f02977ac000676fe8ba3def5e01209bd9fb6488eee3251f15865eb1ced75a34d2f00e8290097ad22a4eaadd1c0f612bed8b9662d1bf3dc0f512eff9e42f70b1a93cf3307002df57fa0448ec6427ff29a58f493fd9e8e3921af54de763de5c134ed97aa6500d6827f59829b6a47d2a4a297047ed3e3afeb17acdddcbc2b8a30f9cf8bfcb30049c083cc4d482c0c3aa6714bdcd9476d1466add59db149d393f44565fbd762000cfdf2c0275fc318e7cd727437cfd7778008ba86c996fdf872387568e6842d00f4dbca83701042902a696bec4ac99ce7f8b99c38b3df29f2e9e1f8a5003646001e75e79aaea8926c970b4c8dec0cdc19b7f34d23dc314bfbd7c0dcc4e88a2d005620b1e79caad9e08a5490abe6beb6ccc566be5fc5b8ca5bc32b88e10a8cac00ac880df8c4996cf3ee1cb82d3d035d4703a0ab6c83cf846eb8389d0a2465250017acf53cd70396e8ff17ce21fdc9f1f3987e4062e946b5fffa1cda30119cc7002a310b3edf6da39e0dd0d29ddc8aa841dbeb1cbaf7b7e6a00bb4bce0eda45500421b82db22d0e822ca5f80daf81d29c044a432756822ccc3b4153c46fe5b4b008b1404ac87edc6d77c328cc17bf11d67ee44c984b85359f5f79a218350a14500d7f901ac07e3fbd4db765e9b6beabe6f2ec9e0d3bfe619445b9f1d6d5bdb6300603cdf9e6266146f329a0459a1dab8663f6b2db76de66830e986948c21ed18003cee2b4b4061d116237fa30d9db1e19ada5facf8e147a2b6f95232bf3f3cf100b47c04b51ae962f53aec4d1ffa271ee70252fafe4ef6513838d17f508bffdd00cc0cf401fd5dd5c608fe873648c46ea5186a3baefe08cc4357e314888eecee00e9fb7f67c4b6ad39bbe03b6f409d53895adb0c9f0c016e3467ee2174e8a06f006e1aae5120400acdff78fdbe8d905064e6250d807a6e93bcf78d5fb07880dc0005d00a66be304c978ca1519807268ca71356512e2bb3a5103af31095afefa500459fbaaab4f1d05f813e1727c7adcb080273619a0cc114245f280476994dcc00f3bb541d6bcd8eae3de0598992143e698decc384d2883a8c23111bc4d5de32004d8800af45a4d28af6c0710b32b8600a095b3ac98c96d33ef5fd15ec730e9d00b474890f3f494be0244e42c0317d619fee8e98973f347cb584b19513cdf171001e001e9854cced02075a8967ac7250f0cb3fa30fb226595ffc36828cb67b340071d6580960fc12628e255d5625c0d118125d86a032c55551f8659a60afcaeb00654c3bf74c6896c6aad15535c0f5240274116575877461d7fbbc6438fcc64b000cd1a783e250f5ee420d396a5a8f3f3c3ad6a9bdaf5329b18aedc46c72ffa9005cd59f24f21484413302029248848bea32b600661e37e105ed74a7c949cce1007c775655aaf581ba63d2eb0ba82cf058c9fe990e215febe10f232c75d5dd5b000b869a4875d4671260163d920905164e35f3e942b4c2134b6a6e8accbe522500b5c33aa7a42e6317ae81a17422c11d957d6b439c7ca062070a4896df13aece005ed12eed30ec973cefa3f5eec35e25cb296cbc5bbdfde7671e2d586a80b78c00e3bf1ea8306a426015b1615f6e53fdcfac9feecf9b140af9e74c488d0c87f4003e08527d8329f7b6c09b276d1cf77e5eacc25484f0e2f80fb5c66429c427b9000e600cf984d593c77df2798b81cb89ea5a7a3f78dfb8f13e7257cf634bc96c003dd163f776f395e45cd7019b966a0cf56adaf16bf682360f616a16831c827c00009fe6ee49738a232fbdc2ef9235257b3d71894b36a152b738e3ba761647140097752ba9d597328dd3cf081d9f92cce63217647059a3c8feb179dd4a837d8f001a9d66fca8e9c8729a8b13ac77efae10a2d782ef5a9652fe5e8e5a1b99413000660cebe01cad6de785cc5aed0fbb1fe12763ef56842bb56d0ffb62c4a308c200ca64d1be2a7a8a4fbb5fe1bbbb42fa77e63894a49e9c91bb690670c75a2f0d0043f5dda246fb8c9793d79208a8f2c57e729c91b62b9ae17e59328e703a050d004924e0522d56590a3049c575dbfabb20ca97b9ec6c9fff4e7f7d8b837681fe001465023304656a177244a7a60ca754d2a783123d2d8661cb82301fad238bec00cbb90592f4606f9e55580be5d1ad6f6400647a921cee4c632bb483aef143fc00727cf1d6315cb105285071671307fb32d86268a0f9af94bb867566f26ec67d00d482ee79fe33616458fc76b4a964c30a02011034771ae075a1af2020fcbcbc007aeac179005749116dd23b487e048ce2d8f7bb2dda73b24a072b140635882200e98c8e9c9721a764cfecd862aee0ac1f01e06bde26b1bce13fbf35e523a52a000102f8d1a5779062bd630bd3e6334ad9ec1034b8b38bb7186a90ae45458e910051eac0123aaeadd54889a28a29bf8f277bce452237d33bc7b7c608804f022b00cbb4f803f5616efbab44963112a87bc81202515078278916b68b59ed54a72a00dc16cdd7c5d65282a90eede66e966a128276b4ec63299c640d7529f9ac554000900fb749a0595e01165713fe4345a79d250a204693e01d98a7f4b7fa0fcd0800dec6bd01940b7d084d8d42a9473b516cf1aa011c51ea694e54316db65b6f13003e5b8355ba62323708f04ca6793b954f29d686ec7163759ac6f0227ae2de8a00638cfe36f2c4c4b51bc87589e79fe80be5857ac54cb97aad492b960caa66e100ad1026eb68a5eca5b731b6c64cdf55a07608b6ca8ea1db9475f1c459cc317f0065f8179ee41263a3b721c4598c564df0320d2077810e74a21edb140c0b3cd400628b7fd2303ada23dde022c29b8c7b36223b6666490c563add93a95f26681d007f27e5d3b5e1e947dc54bc0762169a8c1ac9d5dec7b5bbd658d703618e97120018e9472a05a77542a5569fbbecceb4243cb81fba6c5fbb0d89339afb17d01f00067dbecbba96f1eb2354d5ecf4827ade14166f48b820fe0bf82a48d8d85b3f00c321cffe0241b779afba1cde935437beafd0978d80ffb4d91eec0b3c5511a900dedee4cb368a677855ab6e7bf9cb111eb4a78eeb69f26412ef2c594559985f00e7a7de4e8ff972f5240b2794c2c0b7f0b0817d91dd98f6a664bff2882ad53a000f3b53f41fb1e03185c1ee03e36aaffd4df26883fae1164c5d09768be704f000ddb606860d0aeeb3cd35a709ac4456f48f56e211e42b73bb970f4e80673bc10034c4600a33682ce2e9f420c686393dea87b0347763dc0fde3745059f87434100d1dc38799e1fd9d10343a06bf3cfc8f6b48c5c3377dae2fc404891d044825600ec447ed8ea5d00eb9594cc3157d56c5e7f2380146a952387d6ece86c72b674003eec400c4dced873820c9f73d419a3b279a6ae0a8b4e2474cca4541f059b4800e3495e90c8c87ef1568aeaae6a980e9b0143ea30fecd67d7691aa631e04479007c72b523dfdfa223b39293933ceeaa461d518a9c48d089897c52e01bbffcdf003d79f20b1d74789aaeac9deec2189f21b2417233b5bbfdb77513db1eb3d47200a5420effafdf2aa501f409da602186fa961d4c3d3c50070ebaa0110f212758009a5c1a563d7210dbd9fae9a9b736f9c9aeb402e310eb4e8bb3567eb75ed65b00deec4d6ddc9a99f1efbd75c3e8806b02a6d799c7dc1f5cbcc0661acd948e6400623ec8c5777cd0ad19de53c9ec83df9a8b3d6166cbc82221226c4bc72f5a720049d8de26f456805472b180b3a4baae70f566e29e245b3ba7ab471ee7e963e70023b2bdbc163237d3659a69f75d748f78a379cbfc7c76652ca1ad115eded2e100108de463768f1716367d7a7b57b6b48b632f85b1ace8751900e9107fc3432d00e4b5095f4216d19ac2ff3d17ed1e4a8ee18393110b322001c7229934c7f2fc00cbf0d89502707b33dd7a9367c440fa557b80abd711b449f556f03dc24727f900d116681ff3fb89902ee86cad7a180ed56857a52feeddb38617aa9f569d81880020837adcb1af02500cbd40824085a7ce423867eb1c71e9e74844a49be3d96c00d99d68aac9ca105d2ba67c035c72ae4aa2e38acf4e34224852834251bef04a0037ef4e785689ee6794a359e9330ae9e2936273af29ff1830031ddf7af31707001b8419fa85782bfcd069ec558678d63d2fdfc92322865230babda986bd0a34002e83657894488c28801ea6d6080b68b43a0f4b1924c65ba258e6653578eb53001796ecc71ec3319f05de1edc67ada4aac307735c61eb6a3cc9cedb17f16aa00043ebcf2b67c0cad58c483bca5deccef49cdac710eac958a53de5a6ab7deb5d00233532d6b8b0fd8432786f29ceddf44798a3a7cd309eed13ec0f114c4e475500b0aad69b3c2afebf31f59b873470c49570df21d84383ba797ee34f9f0d4e5c004790010fb7cf8cecaedb2c4d115e9aab4f243e835c6fd468b2a9da2f5fb8a2003d6d883edd349ff8077640c9aa92b4898c867fc462602f287e2e4f8e913d2f004bf4499ada2c4780c84095f4ea7fb7c83b58b547e7536ccfb5ff102ee212b1000ec756d330698865c67b64422be1ea054f3f1fb2993fb0c99acec6a460890000f278913519573ef1174d17c8553f5906ac254abf75ba28c9fa84f89e1c9f7b0083e5790ffaf35da604745e35886cb933f7863048b88809ace8430039877688006ca865105881d19ef60450add7d1f785896a5f113f9223f94bb3f2e9e910a200b43fe23609f6e7fcd00e9498c625a4358dc1335bb82c641e42e4c914f538cf009356d3940fb148cb6359945f544c3bc2f204ce969a81df7a26fa3b5b70b20f00f8b50f5bdac6ea4d6e71b0bf00fdb47770cde56dfdb8866daba0dc0a761156008ffbaa6457c000268fa0b1a259dd1ae85e3b3b9bc06570d31ca0ddd2c7a9540037fd0764be4f146b6f8e0ab8a003693c23c49313aa31155addb391cba7cdfa0094beb8127edafaa0b9e8e8f646e1b5334253d10c388b20415300f08bb775d200ee1743d6740f6a6e59b791420e0531d94f5580dc955df38afbe27e6a0952d9005233eef0bc51d61cf715a778adf00cfd425283708a73b9130245bb4579a5c3009c39c3d687930e33a751ff6bcdb6f9192f91b41239a8989117932abb5ed5d00071f183487302342a36620bce61740ba7e8e0cba0408c92b367e60adf611f95004e705266b39ecc58ce12ef8c6240120196ced08324340bdb1ea905d126a791006b149c07712821cbc92282d6778f5d122fef89e5dff1455ff4bb6f68c7b56400bea8b6bdf1f2cf4d2c67a7e3718d1900e5edaaec3bdb9c62afddfec6dde4e000ee3204f13bab6ed43536e411be997846a5a7aaece81d8392c0202e3faa0e8300c25732337ef1a4560c0b35f8da51c1cd7666b791f4796682b4224fd9525403007a665cad122f159f25f0c21c200120e11b070418dc7d5055a63dc32e3deb77002700c8f3e8fe258d137492dafe076184b71a9ea5932d3de28ae7b02e573ecf00b270e5641915bd7e9509012d25c650a17c8a26933a629342d9ad3b64ff13740050d5fe46890c8fddf9d2397a9eec63d409171d987cc3a3a4ef1399aa0be33c0038fc312dc921116d8a36ce12e42bd53cd57d3a98a9ae378aadfcd8dafe2b1800c12243faf2d7850cf7e61c305312530f49ed136e10c86387e895bee0a6b098006c3fda232cdeb710670ca07d6d1f2a55014dd2ed842159db488a7c8d883ec100838f1dddb72aa1f80aa50c2722201b1786ea457a5037c25f1ae1f9b8e59d9700faae579683523d0e769205bb2166f831eeaec68b70beaee32c4266a6dc2be7007bdb8bc0b5e66fd82234831e3f705e36ec32500d0c6931639240ef733b13120092dc08dff8b4cde50bcc7be95b15394896e9ef93a8b52553551871533c026600d65f948d2ee9ded659b732595b572c6d8c1c4879102b81e3ed31ac26019ffb001a97efe434549af355c7099c4442087d073c3ed0070fed03499f7814eadd1c00be3eb87e696296af6e146882434db758d6a90a9bac3d5b99506c5c4c017252001f99c7774d5bff058ebb267b950a4f740513bdbab398f0e5a08a416da28fc4004b4fa0cde1e86f3a9a28b53353f19c7ce99e9ae03b90b89b1f3caf09d3b6fb0016b3a31e89ba4d9af0117935b1d45b4d112fb0a6f672d65671b87a29520ab000a558727ace9880f4480593ec40d44838d45a42297ffc6e69095a2b9139faa400fc7e9acc68cf29638ea95e5c9352f4dca88fb303bc16da976df68258e86cb800bf5c2a59a0a6894c3a57c8c46ccb071dc9cbc4f0571fa48bbd342820b04e34004eb710f4991b7e2e08167e8a4160c9c169d8297fdd3dec10d65c94ffbbae10003dadc21f2750e7e26c4d2d7ae2c9693835581db9dbd4fce8aa5eb77e5ee56d006d8bb4db7e3534f8e1e39b285bc6af47f371877a59315870ffe5961b1e194c007c3b408563a595f3464cfa620bbe1eaa55a4046475ba16ef26ea3e4f3272a400a5ebb2cf75062e96d46c98f27a9bd8a55d00fd7abbeb79d0fe1b53b33709a700aa0781b018aeea7f7e0ae9bd814cfba0940be6b81d373c2e71816e733498c400e235d8c389708051a00a4ff7b8dfda7522bc29af58cda0b640d200f5724bbe0059194eaeee3be327c2993dfc25c74c4ebb14572129bde9607c8413ce61630100393f68a88fce375d6e5b69d8132f04f1a416ab7d00497ad9af35d43cd5073a00db4eda635cca9c84aa69ed4fbf742f73cc5d7a270eb09d712d8c5249bd615600ba55fc3bc1e522291ccd215cc079f862512e7cff84bdd2821552ac5f65c0f100f8752e41961e381c26194901eb5322c97767c19609bcbedf2c1970a8af8c1000973a4a928bcb3e9731b615136ee3d08b32b9e3d52477aab7e7cdd0b43ccd0a00a4aabf9d74ca29b7c20258e592fa977021f34d7a4c32c828851eb76b27b49c0009d9591e578af8fe4a6b86f943ebf6f0382a61cb158195497aaa731836f8420031c9b44a6ba7859a689791a24660ac5f99de573f24299596e6307326f2c9d100d8b5f6a0ee9f577ea2d72cfaae6f66996a31d3ee261d2c15a04bfc62d7a454002fcd52db50550655aaf0022bdbb031511c2b38a441dfb581d155ebfd720510006704aae3437518352be16e2f6a30c84cbc8f53320cd493553b52f341735e450037326bb2259265fd0dfbc01de422449c8588726e66b19604f39b463a87416b008e81c6e4321394f7f6c01b1a697af3c3f4ee499b945d8a10cf1fc476233f4900c86cadd0be72c16f9e5dac30ead1b00caf76ca585d4fdd754a6b3b1ba5405100b9e3c10edc825f309d4b414e6e590a5806be61afe3b58b492ffd0298ab9047006ffe07bbfacf98deb84720ab1cdfbba872802e8b6a03631849aa2675d452f600419a182b708199314bc5ef0475face5f3b6edf8f915a7052cad0adb77bf5ba00e8684ae7f1e75066403b08e5f81f64cdf293178fddbdba9f7f6419e8e351ca00b845f1e01e04bb1bbe7f7ca818a3df16704d375acb21b3900deafae0204231006fd08a6840350cfacdee2576fdcf31da35c9842f75c604e2f1a92ec4439db2001bf07d8f96675c274ad6a10bd4fd9a57a0b5251bbe3c981aef7ffd6e443cb9000165a441b713abe3416432fe03e17de1de8266966d2d361bfae1d2e91ee0ad00d421fbe3880d5accf182f8a9b45928c6d11bef74238ddac612bbe4c5d326680034912577d14bb0675e6ee024237ccf3cbe93cf18f1fee79592f1fedbce37ed00728d371f1ea4efd2d063d368d695e3b867dc0074bd638b2a14424b44acdb38003c2eb07bc9902f3e643ad76f7c374a757a92cadc5f094896aea3b4b65a979800ee09955b033774ec29dd9fd8fc0930d72011a39726c3a7efa33aa59b5fa531008252864c5709ccc7edabc2df37f1a5f7556a9a7405860fbc3c1c78045b879b002a6064d84eaf7ff88c9593a64d45999296e78003a784692777e5e8650c5fca00b7889d4ff4e38221a48bdc740d2f5728f5df53424577289db0b57860aa45bd00b6cb3c7c1087776b738a5dee1f9426bcff240b3131a6d5512ef09d8dc30031002558b4b2c62051dbf094703050947235d351a4cfe9838a914d0402033317dd00157b86bfbb220549db1597726257bbbe8a754be601d3ff2a1d48f1db516b4900c9e2196725dd53537f5abb98deba468c7c57ff79c27faff0101852f7c834b300440b7f42a083d7cf93d3ee3623b3df55a8f7bbeca1a434c39a331b93fac76b00c41dc2135d503999439c4aaf48700c1187378840c05ea339891903c0bdfa610021b1d1beaa3f7d3b73a2b75905c678635d53235d95e62185e58df657f28d54000a7da390d5994ce1496c4240d4dd5b0dfe517a631f24e4e45af0255021efbb009e13feaeb14a7f3ece4af9301df98ba7bf799b713fab0a3bea1e8caefadace004dae3f700eb57aa2df50b71637d27eec29e39d03814e00d5d8d3c0adf3d7640007850d66c2efd6e7e5eecd32277671909970561a81e1dd9d69ee983701d6ee006858782c61cebd145341bfb99abe6bc40c3b6f079c1c0991e98873887201960016d34531d265b0111e3c1afec802f16f7098b299d57e8339c283c8c1b09d3e0040fc51a616735f7c4367182695e23266ef509708f84fec6300e1adc796daa70019436e5bb64cf96f25814e7a742ab4690d01011a482d95f0d001ff3f8fb993003a29048363e93ca296c660e07c72a39bf4bf71775cb1197a774e76bca47d1500c07353afa52733d91fb86a6fddcd8cb9ed3d481a0bfa6d4172dba6b23b6d2900c11944379d728bef9d17bf1d16a622cdf0471e4ebfa273b0f7a10261066f0700f732e7d1b0a66b16ca449b6faba5f1d6729554a8035a6ee02f96ce2aa6183300c4b5758743a267b832aaec8752d67384354b42aff355b8908213879598bef40077c25c8a49eba5e19947df22cd307ffc151848d2e63638d84722b4c5628ffa00b2212f23a59dfd7d5c580a200168bc5618871c6705b3939226bbb8d01d96ff00a6f818928a16288b35315dbd9f8b615cb48a296294f5a3486e413b45f8c8810039f44c92f2e39fb1f309f87a065571db6082e5da132be45d7aa3ed739007de00f25fe72b8c5f5112625d54af111098110ca85a881e136742db614a069b2d5e003bb88e40d11593f28aade0108c61fccf18c85efa83caeaef6f2ded9e624e5300e3b704c6b6130fba83b1ee8c51154e196f0077c2f9f99c0a40204f36c1109f00ac64d4c1662394c9caa46d85626666f7873ef40f24567b849c49cc1e3385ce007fb9e31fc5a1d4bad03b7a5accb5ad73e1e877edb8c42cd159228512b3dad800771a3636c99d5fba13ce99d5408c37adbb77165d288628a16144a37c4d6e1f001cc277864b91384d43504c322bd9e286d21e4a808bacedc846c8d018344f38000a88db1e496e3b240c2af68945096fda7dfc3294d12c7a2954a92175227fe100ace6510974db1cb373b9dcab1bd63bf826e2c0ea6ba7c499fd6add6da6a9200000c206e8466c34a13851ce3fc8b3bc9bdfd58c574ab7e416b3b0731b2e4f640011f0d71070b8b495e8a54e32deefcb678fd190f34edd98109393e82017d4e400c5cde216015b032ed4cc6b6c1e748ddf89a0962f3ec8d6bfa312b9c2d62b46000206ba0624a363f07f1bbcd7d3b64508c930809c9de857e9f55fcc8d3d35de00ae61063472fb6aa0e2e52b97b932b2305d2608f90b07487aab53ec482cc1ab000aeb940dd6721200b7b528de60bf5539f4a8d59631a08e69f530b00f2656da006ac82322a1ed3f2d032219e61ebe949ae7e5a670de33d6b4dbb74e065fd8a800a36f5885d87840906947785494472812c52f4c7d788089b25395400948832100b85e94b971c4b207b7525746c3d649b8559584352ea3efbeb342d7af94a9b800c8350b768825d1d1933e491697a02a8fadba4043e124c0c26ed2b4c9f0d04700b0505dd6bc632f8de3cec161c111d4c78c89885f825f403f7c6e2d5afb36fb0072200dd5f4774d6aa66909958d76ad708c209c2e2501e522e0516616360f4100a9e719b7a8d6145259e6b8d181e177f17f1fd7c34759b1db760a924da6b20500a7d6ef5d49a13fb1444bcdb04107a9bc68194b8378a5d66ec8751c70d4f474009f745b5faffac80398990d10f03e62e90455c99161b23b82b88c98cf414d5e00d1759f1d3708ea02605e0902d416fe7c09de20a9d024a9f4c80149d670bf20000d219ce06ccf75ac3d88729c3354a8627dd720b1dea2fd6aeebda962c53abd0005cdd91a76f7cfbc53159d90326ff5933c9861ab82ea092f51823db7979f1300128b819eacf6d6de49de287ec64c50aa93f7b0509862cde5800f2349c0a37f00d772aec02d67141c9297d4d304e58524a5a5044067cb852a46377da655e0b80041e6a3ff83bf46c7cb95a22d6fbd303b63b8e5b2a23409d19bf86f3625209600e9195780568ac22dd7251ae6a974becb9cb60e80e70c947ba1f1b2c79c516000158955b0988baa45897b157f88d9caf8a3e931b90480a60a512ffb4a930a18003a323c600e0bab34677b628b669d371a1eda48366f6716f9e040852cb0dd5800443aa150bd8854b95366f9e472b94c079e3c2055f78f5580ba43b90f5c3e1c0048c9201bf077f268a30e6cdff7935ef5417ee72c92508431c72986ccc406a6005ce3981f44325841cc8835141d79cfc19efba7e27e9b43b0207a6b70bd15f7008601611badc5955085e940d3f67a5a5cc285b625bd68ff0866aacd277550be00bf297300c1f4cb2ed6ef49d51ce66403ae657c6cc15692242e8957fcc09c90006f479de53f3e810a10062452431060bea2f1d5bf304bbf59b3f0394a1f4a3400a28340d4c762b79feb79d0645a3882555e1caeb5642cdd71fc2e132e5f22240089fd62c6caedd0d43bcc819783ab4d8f5bddf6a482f03b82d01ed9e3db07cc0029d0669137ca70135ab5578d906a999c2a9ac38ad3e0ef9e424153c1fbb45f0026f89f029a3821ab799715bc34be33bdec47a8aed108a5f02a9ffdcfd8818600cf47b23ed3d067a2f8ab288b56f95965cef11c763d10e915341d194483f4380005b9c28cda31b85078c99e591d430da9d94a3635bc69e8bd6b4cfe49e9679500d5d59203b56ef591ff38deaa430cfa36145197b57e70fe8a3220188443df5b007ec2f06e5da73d008b2b43bc19dbca85cc31b49fc5c9f88815dcc7a8ba749f00d10d4fa0d150661e57407e39e2d814f4bc1b45f958f4476aaddcda481f64af00ec726ada5aea2622cbef1c61014246433c081be1ef3976ac31b6cf3b607f3f00e9bb1eeadefe95a900e4dc34be6bfe6c25c25dbeb69df3229996ac780ce099008aae53d3cfa05e46cba97c2e38141ff81c0860679e28ea001a8a15b27596d500236a968b4615fa6042b64b0dfaadc291b8325c65ca03742e061bf6c93dd99c00b4c9e859949c98b6cbb22bae8ee22c6f85905d565e4804b0139d427bba428f005da9ed0451f9f702d9bb4ba35608a9c546c85f7268941d44091aec3cb5b1a7003dd3d80e4a285991d419ce36145fa565ada47e08bd858b3540e62d12d598e90075ff37c873020682b66f081c92c039565bfff790ee7f4e79eae661a5a599ac007f5a4c0392b5fb1576e2355e7affdede6a77a76e0b280b0c0c1a297093f2d5008dac6c540a8d68ea0a25404402bc02028af652a143ed1b0eae2deef9cc7323005cd819670ad648b0c36f36794cd1aeea901f8ae9c868733a5c90af90776b1f00d542094d757ad3b20c8251441cecb864d49fdb50772e65a717b3d03b2fb51c002d8099b0886a26e77d35ba09dcaf4d32dc7433871581efc7ae8d2f3e1ec6520055ef769c226f6456fe9327745f098949b28c5e232294ee2bc033ef7b8f628100c382d599ea5072391875f99c929d3edf4c59aa0fd9d6073df3de541cb4f654007c15d16297d81b07ac3ec0b58b14498c4cb83f63feaaeaa3744581c88f5dfe00651c5ccc32fdd6abb0fab07d0c9f11583f60923b986ad5058d894c37c770c900e108298d3ea0ba5d995c9dabedfa3977be02705c499eb393dcf287f51cc8d500d9d758acd165308a9aec1a8c509f84d27bb8496a94db438864e1b9d1c6a6ab00d2de80dc01462e885278f04b8656afce0ba9d87cf7558c8356be2143ae8dcc00a0ee1673078b83b21d19c961334695ec17f57cb2b870b662f29af55176d92a004f4bee8324fc7a5a08ec63cd45bbab74a190461fecc47d9813cd0a0e2666ea0038a71419cffbd65dba6879e68811aeb2ec88fff92016f8081542d3b8050ae900fe41937bf9b42f14eee1edbd25dc123c73fa0e70362b3b28e6818322f791d1000efc16d9c6bbf72c812b51eee488b621496d3cd61c8d36dd659eb1f950ead300a00b89c3d60eaa178d7595a6aedd784f2d8d32ebd123f2bc3c4b2c384276f300026cb24975c44b9249596c2a9e8b0864990ed8c5f4ed5a8faf7275f5878774009347b66fd34130f8520901850a178e3058620958a410d6f789b297dc861f1800aad71aed6b5a2e915462123a83eec950b2176ace5d1d9f78306e799a3d9c6c0050a369ee230aad30bc1f6778b4bcbd7f263ec7ae526cf482451b6a8c7b3935005748edf89221041acc92955dd602eeba1e0e947c851d4af07271e86086fe9c00be8da12c772b9d85b44ada0170c1cff6ed2d5f3a8c44019e877abf7f3f9363000de45bc279349cca50b38f65aee06c57163fda50e5241dff5860811adc6b9000b386303bb1e3ee1a0a6ee1afed33f2da48594527a51ef85ef98db95f0bf23100b483bb38a4ff4e19d77fcded10d5da0414df13bf42f4a0e400f3c68d6aa44c006838d6b70da2056a0fa34f9844af031ead211f67b01089045c952ca8a28904001715dd5174b2a34234596024013ff319cddc77fc78bd1d318a956eae7db02a00f5a51109888475abeae2d0a71b61ab515d292e29563d35b9a8d7cc4b63e5a300318f96a794ecca51b17efc2207765a5654efe049b595d7539a0d497cf9a816006032677abad39bf0d58652a493e9af4b5fe2da97dbdc58a9ed3d35547addc500b5a720c523b3cd47b0b0c24ec0eafce79a44384d8cf066cff4eae7197e4c630005cfba09d9a3a60832d8d71c7fa1ffd2e2a0ffdb55c29399e09b357d1716c500646e77b2c8e051ae1a179501f5a0ea1d9125089dd1bd4c7e02a8fb4d3c0355003da451831aa40f7bff796f912bf95b766a66d9077e9b869ad1b87aa394ce4c00ae90c2ab20791dfd85d4c7ba973ca550bfbfd597127cb6a7915540809519b50027ba81262dc611a32db252bc4196781956c8443a53fa80027ce1c876abf75b00d8043559732d06470f4b8a7ad4135d82410ebc327dd8e92071b87b43447560007ff0819c7c9aefa84096ff593f21b83f894158ebf0fdf0bced4b20a248caee00ad93bd1c49c621cbd561022f346865e4e9ec56956a2ee7940df6cff8e5c8780038c5a700cfc9fda87132cb99bf85f4c580cac7744b3e4d523f651edd5fae64002cd1542dfdd15333a8e1af3d11d918f1ef6baec99b1c64fe3b583cdfe7e3c3008fb735e344c75999ab4ae8a669818c09df1cb858f83e2ca070645dc885636700f63a5227d32e7866a951f75798b4a634f25baf83be2d6056b040f95b7a815400e60539de2ed07802e24fa6f4654154fcafe3aade4e222bdcd0b3f76406cb5800b7e84c33253697cbf1d58a0979b3db8b82d686455c4a44fd6844a0b1f7453800393bd217e812911c1f3b52e619d23a4c8ab15997e275cbe0e3bff3c4a95c750076208501e2b11f9b0be1098138c21925c35ac4345b90c26614169b8f6a629200ebd883acfd5fd3c241da7cb4be1de3e86e2fdf70b4c4e7dd0e05c44b9edb93002f7c9d2cb232cd6240e47020f0e0b418873fb52c5521e33cb04a8e09bd6fe2003c8c38e3447019557b02f6ff9ead33d5844e29a73c91e98a6f8938a8cd13640078439dfb9d3fb0618999969f583ac2d5d160c5885b5a16fee536aa4657ff9100e10b7bdeb39bb1f8ee41c97b92369fa8efff1440d32e796f92781596be60dd00e00fcaebb9a421c345eac75093907776757432fcfa2c8dc3bd115d4491b8d000f257b23f58041d7d6fd64d616c55916805b9a7795c7ed0d28ddb609395dc2100b8826797b0ba5604cee59189f72bdcc4ba94490682f8ea11843dc32aacdf24008cd8d0b2eddd83def4774f0f09385ec91172dc1526f6e4f609f12ea42ff53e002dc08547c2b90e481639476e237e78e67545ccc896940c3274387d57dcab53007851ecbc24b067ded869415c24f6a5f18b73b3a99ece21bf9fbb476e50fce5003180bafa6e9ab72abf9af928da964fb7a4745274fd7d156ff88dfc479377e000d058cc585c9562e472fcaec5bd22a5e5105df9dc155a350d9156837c0ffd3f0083020073e7f5dff8dbcb23cdee9a41b74968d7af6d09863b7651ab65009b150029f676d92ff87a066969588d3c47f0f928922625855d706975dbff12fe30c90065e21bda89d23817c1306badbec392cc5312b87ddda0415b40cf266e43e1da009412c439f6ba476621665825432152ffdcbd6cfaedd9e4cf5cc627eba000a100d6e0dd0d850999fc1fdf146f38b076c6e90760b8b76a26252b297516208f09001350b7df330ea90864ab8402ef262cdf1d3bd7e48ff9cf5b342aade285959d005abeb23348b57814005fd555bcefc46e89846c5b5187b0660dfb54352ecada0012c1426d079a7af9e684cde23785d488239eebd3d1ddbec73ca0bde877326a00eb00748a39520110520af77961be4ee2cd9517ebaaaff371b22b36cbd82b130023c1015b2b70875f5101a71d0cd832d409264bd88a0f507c6645b89c4ea91a0011f2025f834c5a0623441b7b71bc3f34b056321b1cada53f60146db7a0865b00ac188de1a8e1d60f9617f8501a3dc2c55fea2417aa543f31d7afedc35e94320093b5d38c873b45cbe132877f1f2e0d6f3303faa9ac21b741ad5e6f140541ff008db37e3e19c09180bbfe627b9eab051c130029ba8be671351f2d7bd9b47f5a002f80222a61c7428fbdcedbc1c778e03b1acae1a8d229c79ae9f2a32dff525800f1c0d47ddbb6765202c346e9d3b0891ba2759083381892fe9c799c01afb585000a4ceeb11a3d20b380187b64eb9f9e7cb440ef4c0752ec7018c88fed1954f00060e6a71b86f89d755ae9eb2a6f99a3fab422a80b4abab3fdfcd322ba692f7d00330d6e47380c4199e73bacf47b80d76001b6331f055f110c12f38149c92f5c00fd03734cb4aa224b8ab7086af3b6d36bfe51b33e4d860209c2eb3717d9dada006eba9473d9e2d128d702120b206ab4068e2afb0caeba2ed5e443f87ab94eee00c30862ad5acff8d409e1ee84cc68f9f7d2ae761f512560302a3b99215a43d3008dc88f78df0c2ba12f4b4307d739d3796ef6d74c65b34a39c8808a54607738000cdfb2d6fb1756164ce0062e0fa46510a8060ef85284897876a008d70976cd006983a3bd39e765d1db499ae069b0b0a3cb639ee443c5567b01a1258726976a0036d15634ab925c4f48dfbca718cb929d04a508a8c38de42e4d7f51f1a0c6ba00c05d59aaa2a464c9dee25ba195473e2d0bf9b2c79b0613d4ce932074798c39001bd85c3b021974ac90cce937332829c2acdf50a51c1de0d8784330f0b9b0d70071a4168fbab09906201b40052902ef501d7053202b91999d9c3e6825ca6faa00f6e01dd15738701a06111594d6a8a8fd71d1bc193133243aa1aaedd5e7025500fe6147d44e8acce61cb3a602fcc33c9024ec3646936522093a2584fe153e3b00bbf9806719095a0aaf5a2c030d90fbf22a113c0b9604c0b8092c916a5c35a40036124855ea9880a14d9f4b0af0acdcad66284638d39436861455d001c79286005e719bdfe47bbec9d404c724552803294fb1947fb93b7222e686965591a807002942785f7fe3208f170e3298dc16b82de00b698222de3d673016326d80428300ccd1998090e37cbbf5139e7b6dae14696fd87cecc47bc44c2563d84b028bff002727642871e43f6d433b05abc81a145558dd425bb8f912da3af848092e006200d232575673e585d90733db4e0c31c6c9cb2ef9d8fe1e980014cb59e0dba98e0028f01ce9d6bd7dd29b9da1df9c9b483707730be1fbe532b2a553e77cefcebc00319ed59acba96538736965f512785a9d65843f1f6cfaead56105cf49732d3900c8ccc5b9b044d02a6c7f7abd1edf4335a75a032ef9fd2ce8bff0e653c2fcdb007ff56d0fcbbebb13602253b6f2751938ba706c89f75e2666b1ada2aba6e731006cc67b1a587953f6c1c5eb448c65153025503b59713683fb63a330055265e7006c9c6c4bd81db9414e06d8f01f9a54eb524baa33d3b357685f119d0b9e5de8002517a2cad86ee8651729999c28d85da56b0a2cd320c42892d53bdbdeb277bf0034f091db46db2a78bf238b0bf0e11efeeff89be2cd81a6fa990f955e99351e00b96b58797bed1ee3bee37721d482cbb6024c69e1ead9ca4864447cc4eb6e02001a317ad5b7b53d181108be3500f09ac214f4a739e1adb315d311d2d065130e00e199b98b03a38aaf9c0dfca981d323a92e2a7763ad964d24317927d8f5408200a72855dcc0835dfff7c8a8ecc3c04e65ada0c103e0c66d7255b19c14fff2140041f36f54190fa20e14e8f28f836271c4c2e48585f46f80c41c8df6f9793c4f00351e28a44284053e678a23428fca61d9f3c1bc79dfcab82c269aea5028555700926ce6e407f3d0cf612348dc3e8a8514896ad14ca7b8426a92500cce77c7a40090f9a11770fb90584e2b0ca0cae5692c5ab3b0354525776133664c3e67bea6008046817e4bfda8ec6ad2dc87ad6d410c7cfe7296fed3fd3962e035924301cd0019c678653086ce470601abff531019122efa858b22187235353482570d12970060824678fd229b72c33098a7990b5c81e5d87666e5edd6185887123e4574b600ceda205fd5045bbec8b739112cbe1fe6e39845506fcb0d15e1c0d3d78be72300b03dc5515fcbc87c5d7f9bf4a2a8d6f7dd3f782d7ccc0054676337954120ce00bd06c527a189aa3317fe5671fcdade393033d94ff797be71ab5f8c9b82192900d0fd9ec2263c8b4b6345a4c18724f6fb2d8dab9f7131e960db2ba509bcb01500bbe077f38313d8f020e8321fbd5777c8730faf8185e8cfd05865742a8166d500a74703b6cf023a4c077b38b818716025656d1b3281e05e6685f8e58d2a0a2a003f81ce2ba7bbbb422d5c5f5b3d2fbfa2f0a4ff66dadfc67db6c0f77eaadccf00ddbf75777efef2aea04ffd64266b6ee0aead86070114d10b3b166209dc333d004c24be1869c166a6e79b5f2d63a1a3efd381cedc11f5b2e3686639044e4376000b10f557fce9521a5a2a85aca72349c3c07b745e19a2f8d31c505fcbede382008255d30a625a1e83cdda08376008832da615ec2f6ce6391aea6cfd4669e86c008798ce08dd7bd12b3d13c14a12de6d7df9a353ebb406c04f0ad8b6a37ff5cf00e2b88d405b1e1024ffb53256a8566377b92753114aa64641e4a3f7cb1454ca001202910c7ca1b286284f6d934e93b077ddf11f4ce0fdefa7cf9a24a19bd5db000de66bcb448781b98de86cae2f2b0a81be3ae607bbee410f8ec9a3513aa20f00a59007f6ef2f2a04bdca9219ffc326ab0a575d236873b3ccf8ed24543376ab0093da94e7b39232cb0e9ff74026b4beacf29370e98d41df395070bcafb3a63f00da56f1ec1044a97e8c2f2b02b4847d36f79c1e4c5c020d1f24c3b7c04a5205000e7bf5823d6994f9badc230ee73d8e78327f651bd6c4e7a7846405dda6c1e0002ad755674f3987880efe6f9962e74d02841f845fad1866283eeff58be9467600e93e3012165f1a4bb69a9f8d378b22db98d0ad430a820c6810a1d578add6e400fcee631b2fe1a38353de9dbda03f8d77f592b60d1bd6bf8eaf1e713a7e38a60041811267fd17c9d6b5a43d9c1e0d9368953bbfdae39e0e6a5d785a5fa2e82700df22cbc733af9edf4e65ba8626976a39b0a2cb7e66ff8817a06c74b435cbbd005db63a502104bfdd239d53b2e7237ab08108c94e3887951f8fe043ab0479c1008aa1cd46f939b69479c31a03a0404adf7ec5c9abf7be4d7874b85e719c27ad00671f1c95442d79d745b9a5b1d3c3a2d2f328eda2c52d738ebc54b211fa5ed500c0f10a1c6fd45497f368eec981126c648322f15a44ecc7de5bc089d98a5b6d00af01bc3fbfe57bf78657a459fc90d01a3165d6529d7ceaeec13bb9f94ffd44002d4b61f3903ad3ae3a9736b012ea906196a44e165dfa543501800976ed4b8e001defd6737a47e682eb4afcc28aa064ce8440ce7ad4fe0f0f3f5441fdb91595002be3ae7c854fa2adfc4790ad389a1f72653ac4a8bdbdcfb0bacdf4cfa008ed00331e6d8f6871a32ccb8ada7cef0cfffe8794957426de7f969abe4b1319937900828a93f571dbea9bc7eb9d891ec856d0fe138f1300ff3db6a9a7ccd4fcc2a400f73f6ef1b2579a71402b082fda7399e3fe93aa2bfbd83f1e74173a17e2bfd7001c5a196e476e10afceb5ce46e05f9341e89054a6e9aa55345473b9286da41c00da479d6989dd0e70aa2a4b9aa8d32f1286d1d378f94ff26c6d634b6a5ac77f00082c7d6d88ce8e2bcb4c5c96e97896cc05b2026ae2effc44edbfaded0b981e002f78745c0f6ef10d2ca59867d64683f7ffea9c937bd1b10a3cb7482c360bad008bf29aceac280530e82dab4ce947e41021601874121aa0e47140405eeb4e46005c57956ab1474f44bffd85a4d64f2e71bc4ae2063dde5d47f4ccba5be80e880005ccdbdd7e8f9d988c5728f2a2592866ac2410be8b934a0f77dad03edf11ab006fec00b8b43528e40eb3e4d5285d255ea3c5ac9c1496ad378b751ee7a278880019c6e0da3e53977fe03b50b0d7b3ff4ef1a2271ccff68f628cc3bfc0fdc4c00063325ecb022b0edd73df29dd8e100f4acb9ae67223efaaa4f1a3f4b9bc318f0036ba22f6b3feb41d5430335c24cf27a9ef4c5eef450f604cfad9fb9c2f504100fb2bd282165c71e9d70f05ca1eb6435a0c2c906e825416d2c5a3514ecdddbe008927612907132489894924f4e597f9d8e89dd96773624eec8ca1e1e9a445e900be6f066c7895415375848e69ae4ddd2ac39bc852ba4f7ee097352e5224df8b00f85a0e11b7af7986a415fedbde2b901826f67eab7f8c8ea951c8138c9446590029b3f5565efeb135934da554cfdfbb508552f1b1806aac262f6217a601041e0041199a6877ce2c31f237870dd1cda014bd0c838fc912c0b381b04a7ba60ba500f8d944373501892a3888cbfcde4b6dac2ea68b943d951bf8c0c7536b40e4a7006305691aa80a27f90889624cc0c5069091c1a203bc38f9ac5806135bdcdd6500b50665e5822fa7e0e37b21ff93ba9beab925ba4cca826fcb8b850743d376920042b1cd6cddda206ffc47fa94c8e3c217860fcdc4edd3db4f8b4b4daa4957fe004e5b1d6cb9fd3c8847a98bfe38f182c787a7bfe64551d80b8c9e2012efe05b0023c22ccc02d6361ce6ca2d9658d9a7299c566ed24515ddc51f4d3d5335f9e200150dcbb75b1fb42d5b2f56913dc3313b1aaa1e42b248f794e1949a1d612e520061e9dd3450fb1a164eceefc268ec4e2d51baae25144df843f6e3d4f6f3ae5b00c09673b63f6ad7bef6ff5ffdeee77b0fe99e7e997d43da7d52cc8566354e22009562b2789c7837d4a74a26110391009c8f944a1b98021582401e22d71b8e240032135a43b3d4da57cd4459a5882d4500cd065674ba0c888b0361b0c44fde160032ed5058766d9618eae86be79721d770f07704cdb1a3200e37ddc68d86565a00e971b48dae67b2aa45e01076f9d0fdab33bea54b88a07a02f74418c62d266000059a424b251e93e2f96e67806fe5854beeb186cea19b204f10d2ca72b61dc7000fb94aab739310e050d08d13ecf8d938e70e3e7fb8bf7976e91faf3d1c142500fb1feab1003375a2cbe362136956459c304e201c81a63628d5bdbd3d4c0c0000492e5741eabb3f9b2806c6025e9a9fe06551b7d0f59c13ef16ef06356d341000e7defa80bfc80c014bf58bf0e44d22c3fef1e808bac39619caee8d675020ec00a42985cf739ced161c3651fa67483d533514794a3953e4cf7a2f273ac3b95b00980155adaf0b3d08ac749c2981dacadc8d1b899da116c2ea4f85fde359786800db685f59dae0481b398e2db640283da6188b2bd284c8c07100e7ed9f07f74300544b0940a418e2b4008c4e6dd9ca1681f7a02f4624f6a6751dbb94ef1274f70035c36ff437c7bc2bec862b63e992b579b2fd5e9ca40d054ea9eb93adc222f000c57ccb7478da83ea95b32a05cfd8b88f5342059a913b151c0c3ed9cc8b671b00231c6ea8f2a16418586d7ce86d1599b4789d50d56199d73c3567ce99471513004c44197a73f79381b4a778e36a37fa98f9c194007d1f4a1d539fc0491f0d3e00218fa9e8b1e432135806a53a4576d5053a861b6046ae8e8b97cbc92738ff9b009877b3f169745f047223b29e6deac912ad0fc776c71cb1101f01c20cb80bd000d3150bd8809ab2572dfa4d3b04cd90b3c2f4e0cc69c778f5df979c6cd802300081220f94d1d620ff5d76ba133f2c5df9318d85a28e00b6915574aa83a7ec8400ff539cc97af140635200700c931cf38c9417e59b80977365eed4065f238952000796b647eb7ddbe687bbf8d1edb04fe3d5c1acd50c2ad3088f09b450bb529800e3655474739718722e34b5edf1a3eccae41d62559201a60fadabdad486cc04000dc99ae8541bc0846f5de8e1132c326d071cdaf5591e66b3908902dfa0eae400bb54015b36529ba39db5f81e52008fb238c3ecb5158f34a819d1670ff68555006480b044c88c731c7a76b46e1346b72f855b21f8327d194c42a4bc1ad7a39900a937957dd3dbb00bc1c8ce618a9f65abae05fdeb8816f2721ebf069b99dc8600051669038e127372264f7e1d14e38c44b46a482750e6ebfe049ed6c6633684006dd92493f3becf0c08f1dc6d0503567d0fd85b6d12bab86af720a2872c05cf00bd34016c0901cf4457189e47fa24703eb75063903fa1034e99547e53eb32520011635b68526a30ada2ef32561506d1c17ad58fcdfcda04c6d6d92135e7a0f50004946d91086df06cc834fecc5334357ef88ecdc33c33aa51a99afab3dfc99a00261e2262ff99bebef81f5966fae1a61f2f263da4cad4139b96936eb6805ed1009637fc5f523977e5186b4b5011a1dd9a0fca3f904543585839def6ddf2a589009c9f4000458f3c38e4e5de1f25edecbbf16395e134622a6633291b70539e3500f8facc1947e8c791fc12fe7b512660678e9610191bab9ac28fbe7b03ae46ac009c6e8b2b6e97614beaec7fa2edb631fd54b7c1008e13ddd35d75928b1f316a001dab12aeebe310e439d735de83e3695f49f4619e7cb63bec74491a80606aa000291b4d572e60e15cdb4a6d9a9276cd55424366fea4f74e431b8807bcc3e08300babdd2ebfa51e2315d59c59a3dd27501f7879c030ac94bc1c78499ae65082f00da3d14e624b78ec6229630084092722d0caf3eb46eced7fb5b06564cebd372000b2d5c8d7ffc98b9788f9f15f126216efa2fd8b89b7c83209cef63dc304d2c00a3de8c49fa2a8970a3ba29fe2466c8fc27fcc4120e01116057b541f23054fa00163fce8b4d2a574968858b3a325535106a4ee4ad18b6b9e9d1834c820400a10026dccc20ea2cd209d0021d245999eaf7bf29dad6bba44a2b2fcc1d2b6099610068fb2bc9a07090602e86e40a1b974354f6719d5630596e58fba44121b6cd2e00535c907d01f5c3693004c3434dc2b1cfc36e4d6888ae36d1378fe2262d9aae00d51c59d37ce8680fd9c054bf90455ef9777ef6da8272c1249548ea858ad49c00a269b911a5bbb5e2ceb547468c8e3414f3398dfaf097f51dca9c1ea2149e78007f4b47382555b1298b634c7e6cbb29fa0d4a0f1921be8f87a6c4fcce3b089e00485e6c8eaf679fc2d66bfc17e6fdabe5b98e819b0ffc2ca04870c7630ba65000de8747a58109d94f144b7dddda736d8f43b92007b9b23c4c4de3d22045ba7b00e09fc6669be1a7f20939f466ef0bbb4a2a4ba9228640c58072765f15fef2e4000d9799534ff72ab57d654d0561e81fb39fed6d68ce547d5cfbe629e229451900bdb61752402eb87694b0f4d434e802bcb148be0960bff4a5c9a0568e6d6bee00518090d9685b54307e31b03d46ea76e2a271129768d827df6ecc719822a5750013d07b293cea07ff7dd85451900b06f9ef75dbf2ca37b1609dd705b6e17cf30022453df34934509a94dab058aaea60f37ad73006cd8abea6705156ce711b5800f220f712d42da63daa442f2faeb3ed75d03300db15d5500da04bb0f40114fd00ea670974191f0427765fa2b39d24eba7e25aa6b5a4eb9760a6f84d016f0492001be2b9b6291948d09ab8adebf3524aef6cabb464d45b12750daf70c1e9aa7300e38c004dcce0d91b3c55e8040f093c16dc071b65a32b474eb811423370290300cd69ad3049d20076911eef02cdf29b4aa8cc506f22c5cc1d7a758307e6d7d10093bea3a4c60d415193b30e89321312c62ab63c5f4d958e9bc282ae98ff6fb000ce7fa5a0eddda6d8d18d2509bcf9bdc1963f9bede524d59cd6376620f9f56b00521b5e2efd1b43c151ec90183c3ab2fbc3e225bee715552b6faa6033f70bcb00fb6308d38785faf2a80f6ace0855d261ae0cb360bc5939efbb305ffdd2c62d00275709a514ea4125ca81e28aaf85ea592b86a8f0784aeed366e8f0a299acf500d7b24388b2f063e21d7b04cf226a59488b1213f34d2ab05399fc1c05e3589d00302496a43dc2ae93d095e659fa743e17600bd6dae5aa1b4cd4c52f44fdc3f600aeba2fd52e8dc8ea720fd0362605ab8423540efdc04a98c3cef02bca760bf600d0b57aa1e5199acdde3c39fd6749729a59a453df6750c4ba89508e36faaa33000cf54937ecb441f34ef7dd1efb2e8412009a5258027732cec32529af91079d00c82b92260e70cbf4038b3d57181accdc802e2b1de0089bcf5bd7a8ea982dc800bfa5c18defc45e19c4bc1777bb75ba79f25d32463d74cc4a4cb22bb09b3ddc00eb59a4c7f1521e6e7282f828772053041d7522df21fb42795a041169b33b2000c610e7ad1cd21c47308cb83a5da99e7fcf175025851aae3c02bc7feccce0ae00a49625014b738dcffceed7ef52ec85ed2aa408823340095c2dc35bfc3c22e0003599e6ca421eedcbaa04cdb1ed0ab49dc1ede38fa58d19d92a8175aec74a5200253ac705e65ebd7344c434fd839530dd3395eb1a26efcafc721bfdc2565dd900b014bb6df3d0927661309a78985d1f3c8271ff3ddf78392a269c83ccab68fd00e0cb790fd742f94891d78120600dbc77ec290a80795a5324d8a70d165dd19900c5e5f81c9dcda763bc89df9a364db36538f61dcfd9edffc72239c286ecfaf50099a888aac10aa34bad4f26439bdffee1223d6e8de534cde399a07b77235982003302c232653fabef245fa839ebc66303e7dcbff605d51375b8d6bf87ef0ff4009637d0d541e96eda98fed92bc67114fc5f21151c194662a31e44a07cd1c355009713aceedf474028fe799cd3aa98635264d66328ee0cd041819d4cc2c98bee00a187c430f96a6ab5bb47770b7959438d513cafb1db32806b45f463e4eb317900988692a371fec2e3cee04f4a4642b5591b293f7447cf466968acc71669b76200e2a5f44077e77594a7f1f1f68353f1898321771894080b05b80c9eff8d0ca200ff29a2208b4d1811acd515bf4ee9c829970d6a227124eb5dc48dca7c6ad02a000774ad5f5b01007327cc1ff8b3b959ba298a09136a881a697da34ea08daaf500f6fc6e6056b749f94e2bb61ecaebcad6cf6aea2db2cebed20f45b310ab8cea0014db6cb2604d3571569afc5616b58ca04d55706ef368ef0ad608c84ebe8b0400839d4f0cdc5b5828f41237c5c24a6c045b81a7f1805c8c3c5b6830ba3d82c400579e70bfddb7fac58817d53c0bf02f42844ea7ceceed5155455ccbfbced11d00b22fa202fdd2c3f9641f704e305dc93675f6f1426805a6da21b3c33667e6a800a0259f4ae6507fb83316e1c23ed4781af82872d63d8c6771eec0887522261c001cf6587c86804de5002b950dd850d0738ad3240b56f4881a5de85937d6f28400b7b96a9ffe28e52e94ac654b0a85c3fc45f04a85b9c106f8a59525a8b8faec00424fd508233c917dae99d9377f96d82b75b7c5775355f1ace8a92a062641c4003984f8b4b8e3286edf1cd9c844807b808a9d3cac327931a9fc2cb75dbef7fc007208b30a771c41fec59850b3c8a24ad1427a4cbc352d39ad04b1d5e3a1eae400e793378a5ae8fb78fee511c6f459add843233b63c10622d0a90ed5b8d0d32000e1c04f2c22b4e15b91643c33fd0cd1b5a6b45f85d42bac9cfbf73d7f2f11a600bbc70fd7c90ffa0f6d1dd5bd1fb7baa86f00dcdf466a019070c77f5ccbff96003da086a71dd0a62559e65704034b94069830811ca2bb4022d42de353f63f2c00bb2875f27d05c14edf7076aeaf8ae7baa0e3373d035af24324f6f6c1b802ee00c6173d2672e932e72a8224626d8c89d86a97e715db500f2d9d680930a55e71002ed680373dc04590237758f5a31784988690b08c17dfed9c0d756aa1d233a300c8f74fdfd1cfce427c5fb02747b481ccb4a3ac34c2cd2c304ade9f4e846e2200054b76411004b8997e301acfbc89787daf81d80c6a6962033ea6f6c1e747290019eed6fe55fe94a4e607ccb31c884713033b821ea13167cfcdde7f721c419d006e514aa67b5c1232e03f3f1a188b0805227b3dc84841299dd66bd7ccab16c90015dbb65a721eb4cde17b4e61e7447d6eb2a720e3a3d59c45336f09d71c9d2b006f614f433d2e1cc9a325e5e33f525102bc80cee2bd7ccfd9a5e5041e68dd38005aa26d15ad4d4f8b69d47463f36cd3325f846b4cc7c006e39fc5c021e4d46c00c853e13ccc4c2c0c2e99c6d75561acd5e373ef64c7ebde909edf6ddb54c10c00ee2783063cd494e0fd1030aaaf450a1a8e69f2091b793a5c0c6638d185adc0001ee5214378ec5aea4dde216dcbf5008542a2e40f4c05b4dac4f5928a09d8d80081f6540f943f4b0363260dc986acb016128a7b6a56bfa5b631145ece97ad5100eeb283c4a3ea73b41587e00a4ac43af764795a6e56011108d734ad256b58c70047280ce36d4280909c3d660a1ff729ef6e242b50693fb9ac93ee5e7c914ff100ca55d70cbc3c3d5898818294e4f91290e727c8cc14899cb3dc6fc8cae8e52e007d81c18ba1bf9acb7e1cd88a67c030ab237aab9e0adab89ce299872ea2abad0099b8097fb684f8b31ac650eadf3d41524a085daf9dc7a75a57d30625376ea900d05fefc9ac224985731c697b986984956d7c6f3d10c19efd66468b7cf6a6ff00943d692587cd53ed60c455612c3d286c920f5089966eec876be481e0ed5f3000bb56452dcc3abeea0505ae17fbfc4b7ad8c689cc2eb7464aa422e6a5d29bac0099403692c5852600fe2fa0807461111a87d17f88de1d8c6883fbfb132cc64a004c3af403ff9c0f7cd5aef933c4fb23ed5081f4bf1b20990555c2e0fab6319b003ac6e7f93e23397233d063b9ce1c3b15953646959f53dabb17aea2435d204600b7df7be2297a99ce8430ca242b153180fc9b12be3c9b8235fe5b5162cc665f00d2afce08302a381dac6af2b262807f46f30bfa2326ec6658cacaa3f2c833af00755369b9ba4349a8bd42b132620f7d6dfd2b430537fa79b38fedc9a3b8df1c00ad5c072a46c52951ade77e4a5241e5ddb8c3d2d3d990af3561bf303716d171007089d4c95e2deef8519fdc03a8b8f72e034e8e0a16a10498c628282e1b618700275f88355982a44303168fd7536a6e27654eabdb6848d9ab91205d56b2edfe002f406fbcf575a70739ba4c9202c792ad2f88ca4a88ebb09493f58d06c964a2003876af82c89d3caab84f07abbe9f56e8aaf3a1a393a60eb456f79a387a25c1009e12c530798c755013a073adb2ed0dd144ec66e8293cf6626af81fc520d3d20047c052281c452784b5c891a4a569495841e3a297f22223e0d7aa4e8f4d90d100642a50b341cb63e72883acfcbabcebf79c0a965752e090269058e11c776b9d00d9fe3a4f9733111956bd1c53e397ec76f9578729beaba5046a18aba235b11300842d531a8e809c05cdf3d7a33ec0b5738627103789218b15526e012efbe24c00edc48d8b8e464cf88edd8e3bf3bef55ad25bafa7d76fbeb222cdf2738e7e0700a40b7e0b318463cf491707014c232b2be24bcf7a721db15077102db2c5a2f50085c57cbb8722117d545133189572fe8c71cd6df8ee34b553501ed5945cbb7a008a70687aad09c4c1f2e4aee315fa1de1d37abe2fd47a3f006f7cf2860a6b9c00882e4c4fbb7ee7f987462cbb694591c764802778330696c26c5d07789b9120007d604c7a8c6c3654f1faca9163d03c4d73d08fede7a24be3244a8f35571b96005bd8d4cd11c8b47fa59384a79a6f7398aed6d772a9f08c370021689a6dbcde006b0a38a387f290088f3b140e3c8a850fb5453393fc3c89bd7e944d79254d29001aa76379731b93c9e159f6be337741af606f00c9fb723c3d70761f6ea18151000d90849e323d1545d1472429fb3b905354e98824966cc44369c3fb3af34565007a8389ee37ff79082a92bbd2722cc792ff3c70227c1429d1df733e7c834f3b00f83c325ac760c52ebfe4ee638ae6cb77f45da610b9d39043b307f2c3907a7f00ad182bc8c17c4e3a11d19faa779b547d2480ff846522e33f0f0c49d9d08974005b82fe04789b847814c210021c4b8cc4f7b1f169a9766f07fabbfb08673dad0033d0fe7c5ea41187545676e5f6ddb46cd2178baaab4e62a336d6e787b87b3000e973953cd3c8ffc9f51828941cbca649de364b71428704f68420a862909eca00fe54d5d2257c12b31e0b772590a2902d468cb5ec85fd26784a297f00ef49f700a5cb8fac880d254d21b83ebb10a4852a1e10dc4dd8991eab9c621415d6962a002da59d1bcccce5e7dfcfe6cc3296bb6371f0a1129ea7697825df54acc2c85600c47521950742b2df20e82e49bbc6d82876911343652f997048c1cf0bd14628007a6d2540a51198cfcef1e318200509d671799a00766025bc30a26980c083da00174ef04177353ae29a1522c9a5b3ff43fb082ac2e4cc8c53d5ceb34aaf71ba00db897beccf13683f23070b932033196a509b8ee62c11bddd5a67acd495e70a00bb1c9f8c0f9d041341564ec8ae4aaeb548e5d96298818b028a71cb29374b7b00d95d8c86313a14dd3dbfb74e246adfef78edbbc1383a86e1ba906c406189730050491a5b1befb0e3820f7287b2061172fd51804787657003f2618e9c7158300065a4f0f8c9d8bd974eee5c3dba06caabf71c775bf5f1dec81127e6f8102dc40073d37b824403de02515d147f398901d3531db682e9c489c6ab3519bd266db7004c2e8f706605a246604dd298c92c5d62cdd6eb605bfcfebb292c5dccca8eb400fbbc876c40af0f4d6b69839167150b9e531dbfe68d88e091c1e717deb9e75700c8ec6012e5b307f2df4baaec48a9811ee0ce8237039a4ecd7792bfe304b52e000c208f8c81c4bd1738ac2fa5ad79d9cc5fad37cd2c05792bc619802f3abb050085a571a94ce4894e276100327ffce5effca01584bfcf0162eff03ab904b1e600d1a03111750e0977b61f860d56d2a1801e67e46e19ccf31cb061d5e56ae68d002237ecf6161cbbffad4c845798216098043d26d6afe91c7d1bce96316f4fc800caa7c0db7b8362181f280ec0fa0014f5610473cd7d339d3b2a11b978fde9bb0072ea9fb71d442c17a4dd105d29528081278775eb86dfa54d895864c0d16c74002bf746b32e349ced7d1bb389514ee03dc13eaeb77ec72652ac48caee96c75700f5aeaafb8784e32d3975a1582a2a4b316022465aff2d3a8d365a2a8379c6530080dc6d6c1cb6b8f0dbdb5b92fa67a3febd60de6dfb25d0cf75800675ce715e007b26c738847978ebda93a76b18f1c1679e85647231c8a99b92b125ec61831000f1750389e001dd45a4b04604ebed0927f661e5179a6a27f8bda35191e29b3400eb9003377f67de461014ca2a79df6cdf577d2e64d0006459216ed4cfbdebbb000f6ddd134d26ce05420bef6ae55319ff414049c282d70e9c2febd8a1aa425400c248bc7d13396f4dd3c2b217eb0a890bbbb755962c972861f0259068d6cbe200bcc55c5ac66f080efed3eede871cc43c8657b8eb81082902478bb3de29fcec0078711be086879209c0069bed1ad47ed96a3094476d3e197ace028e54c29bf90087b5f9632593c411b59e73991b8d164835508eb45b62dcb82bd12ac5c828f50070aca9d000878704d40047dbef97daa3ff8b16d221a940ff3e338425c05b8c00ff4f46401813cf6bf87838a7657db80e9070f64763861ef515acc2ce46b4e200a224d3ab95e0a05615523adbe06a887b13516f87cd6ed62bae35f92162a8cf007b133f49fae570608fd4f40cb4c729c9ee61440b7ccf52edc412b3882733d600021017700eb53ba31fdc250f72d213541e94f41f256670de13da5a75767b1100b38563c108cfd1ea8862bd4b35b5f770eefb290c75f9c6051156b5fa7c17d60040799d25981f9f642c6dfa3cf7717ef6d70ac23fc99996125770fd80da704e004590c90b174b237f095fa89dc9da1ceef4e45f79391394d25ea81ae3becb07004dc02fb48a8f0ba7e38f8fa9b9e7c2c93700b7ae1d424d2c1de43d97e95ee700f1f8a9ac4e78db58a0b9e2e10b21fb5c462803a21ba3a147b0463f47dae12a007cebdebf220994e86de03287a410b8491fff899aad1de33db3fa5c81576bb600fdaef9026560a2ee651af96d130dee9a367f936245a372822a6af972ac9c79006fd5207228c44621a4adba861d67a2ad68a6ef1efb98676ca15ce21230eec200a43980e947cbb18ec83f435db0fe8feb2e62d51a000faf399f1da7e3fa8e7d00a597bcfd96fdc52b24d29f67d21952b229b5133e7374be29bfb42bd793c6d000b7d8a4f411102810ee110f55314debb1982567ce2d817dc7c32c093923d4db00d0de93475879301c29f5d9d1fc74f011ae342d31b5648fadb338198a55bb9800d5358ff22f9be996e6d3bc48a553d829d578246dd809305b45d7dabf1d7b09008c46d1083385d1726bfcdbd3bf9921ebee2dfac87e5b642350689a6a4bf3c0006a28d2501d1a58c76fc4d6dd8a28bad56859cac0481ea248ba440df419230a000bf730432ae8895ebdc521c491d83f22ca6389eef7d298ce1c1438bdff990c00be1cdf87a3b4e09eb96d1939296a044da7abe6f3304bef25d6633f04a8046e00ca5d32ccaf571be350054578a1e6239f82fd08da59f32b25dbe28d45a54f8200cd7e3a0753cbfba240742df4daa07835a893a0f38749e2c8d83ca23ddf706f00cf06c573f00e74913235a077f7a300bd4241b8a9a9a41187a20e1c194e32ea00417545f4bab79f3fc16008a003eab63de427149a783c78850c2e1a3a53774e008fbdd9d95b5f51603ad4b9554d4d51533f0b5ee68959c764a08bbc496047c500a5ea3132d5479b3482bc6b50b500e6207b827d4176bf3281a58c4b8964f41a00d9a32cd2d8daa7b92e5ee045a03aa4b3d80850a665177b6bba31d032d2ea9d00de83831819958559d1bbc2f0fa1067754dbc3dd9d5c0ff7033ea6a951aab67006b82d5f20a6602fc587949b64729246b8a643f356fe7321c2170b5c106180d005713c73c3f13dfb6a4b95cf74760321d784ec9cd4a3f4378777a1c29a61ecc00e6b2a5281b4b4c4006ed39bcd7c9835f409a919329f7e12a1fe5acc7e143c60092223f4da10fcf4b3607f6fb348cc1e3d77ee739142fafc3535d40bcc8e6cb001d9b9ca26a2b4a47c380bb8bb37aa830a44f46e0de279343bb819332d0bed40014d5bb9b42ac0be798e00392b63b1b39e469b6d614756fce91bc64beb5244500973b68df711c521f04c9ab1366ccb7e71efa974469f029b82bdfb8f32a3acd001bb430d8e0476605e18f175edf783ce6a7756799f2758c62c984b5f0e984a7008e09996a6d10ff1ac09e9655004f4d7a70fd410d83312ab05b49ae36c004ba00507635aac4d7b891d6097c792188c6a879bf2b8e1b176ef27046aab420866500da1653825f7b2a8f83170c9a853b8d8b8629b2af30b3ddc37642c27b96164800e8b3f84608a436a7c7b055b0df4563190a05e4c7d8a8c705d3c52019e63fae00202ebbefdb8b2bd9583ea246b782063cd9ea112c84a8153c2d790fedd61bd1001cd2cce30aa284112e3a6a844bf6fbd3a3cb2f140f5693bc42b20420a741e80018d5b9d149b8a5a35086ca5d2cc4983989f5c8036f7c86b74a309369fb82ee001cf8c341f916b429d6101d27080b3acfff14ca77f5453d3c58aab23b12dd4900f9b9c79de2a2ccdf97b7af95f015058ea5d407cb2053972d8d04dca3d898620074991a56cce1cd127c1d50caafc359b20eb7932d670ec6b7037f52fb31deda00a54a123c4525c350b6e2df0ed623ca80ce33fd449787f8868a20f7dbb3e722001f3dc8d432f2c587452e77c6eac8a526dbba22109c5576cd275833ef57642600f2e8cf048cb97c56402ff774ce800e8b2e2338301870839ad350614327dc060055b037de545af424579eaf39bc9e58566326d4242866f984b3b048b3540809006bddbfd3c865130ebcf60d9e90ceae0417a6e7fb0e0dd3ed870cba1a8c05b6003e869693d8b16b33387672e4d14d6d9c180c5f088c2616686be7f84de7f2e300850e12f7b736b2e3e56b177d2a8e70bcf22ff3f0658a5f36e673f318e8008b00247e6d5f86748d15e6adac333675906cbedeb244df62f10ce61e859c88c0ef00bdad36ec686e96235dc2477cfab0987b803e8b52bf6061a5ddc419a993548e00f2b87469939bfc89fe6225290d3f05fbf691667e8fb7411d48f05541945c4400f9da36f7c69129f129a454d5f6cfde06e7a6e722373452663268362b5e336d00ecd848daf66d7c2fedb670020f26e213bf3467398bd447624db575129134cb0005703b0cb10456126851e06cc611fbd3e3ac389f03a2df0d68ddafc55cfcc100d3bef6f5bee4f14d3bcca02c52163137e53dcb2b8a0315711591dd8b84622400e7930e23e27c8da4ce024c7d5cf9df9154b169722b1d9f6f3d00862fc4588e00f89835ca27441d0bab037eb636cb7eb684f5d126c850d0c68c98decb692ac00030c0acb9e24f295c0dfa49487a22d07166e3d3ec165708419b73c56031bcee000a9b7c37e49dcbde86d1c2d8fdace230533c3da287c56e6a143da76a6d824900b01e48d9ecb841040d4f574b9335602bc6a4d3794e263bfdda4cf20b2fc05a0018499f82e25a51e27df46cebea1fc78f346b5c05309d088f0da6a650d5fb08001aeeedac7d5e0ccdd67a0ee207a54059d8cf970842ec118aaca4608a1338180062f916b3fc04cd6f5508ec8e44b7cfe6967f9cdf08ec0388ad1fa5dbab37e200b833d3c82df45604a65051e64552888769ccb51d4dba4760dedd0dba7ed0170084c4c70e5be4bda029eb8fa1c893a57381cc8b51814d890f53add656e565040073361525678d2361ff3c91c4423eb5788e65f77c57a5aa0c574c47e46afde7005d95105f0ec7a8e9ade5c833a89f2cde9b80bb450ef1d0f21a067a9c508ca20037a903f920f04bfcd0995a2a83303acacba27c42936a72828f44ee6ee498720088e7816ee9969010dd19499b0e3d1b287b1e640c0f28ce9cce0dfb35f2b7b8001be3c6d4e33c1d217fcdd97b6f9e737ae539de68dc3fe82b04c487ecead9e5008961a4f7e6bffadfb4456204503b6cdb571fd651d3fc29b98ed730a8dab6f400a6d3cb12b903f76987c8fb1345e29268950d041658f7a9cd08155289c997f8000a7e1fce7142617c96c7429be4417ce0a7c0b49acd5e912121d42cff70daf7001effc24547b09a3a2730037a5dba6fead9bd703f5b2343deb795eff0a7955d0049f4c5669db52589c010f4e2406241c9d65c8ad14f69bb7cec8c63d4166f4a00f9f974a9dceb1f011b45af3d2565652f8566bb2e0829094bdb6f5073f2dfb0005a9daee79de035d499657df8ab596f182bf83cb9774c442a67f18e7a30dea4002ccf84264bd8c0e27be14c9967eda9e450a1aaa4ef5ba38993cc1ff4f78b4e00a12c0741bca53149590c77f7b74c5b36d34f003dd549e249c732313efd453b00ea1b0c4adbf0b529968ef12e413e0975894cb32d90b2a1387baf811b7b67290071ba477d7e6251c390d1ed645c56006a870cf540c015d254182cf6c2ecfa6a00347d711cb2da959181625f71889c3aa03ce0dc33fdba0b90815b37812f2df7005d6ca4e0cf89a63b1b493f9dbbdd5ae3eff0208c2310e49a75f6566a228907002ad08286a674488da2f5be6690f4adbda2b5fe3077cd3928ae0fb497820e7c00470f7b585470b2f41b077d1543c373b554a8f65bb8d000e598fca36cbc3d1100f0761a31fcd8b1d2855aed9feca88f0ce3aa81497ac8bd83bc0b534e8c694d003910a369a7a2e3c9eda356aafac15e20d3ad9c69caf337595d78a9e5bd776a008a8fcccfee98ca76f201448243c0baab051762a12e17fc64b5d00d84a72da5007e217ed04c90c991791c4197abb50701cdb7e48d783360e332d06719eaba50001e048e6a6825e7e281a0295872d646d244284db186614e63eb295f86ff656e00c13353f6f52856762f01716ed0b34674335ffcbef83cf9fe2524a6f848df1700845d51edaa86ab5ea659734ef75aae9418922dc425c1796baa10a996325b23008bc95e462e91ed771a01aedc6e0dc5064d0c4771d0040b0321dd990102dddc00bd7f61ff8a029a4519e93e160755e2784c5436fbcd141dfbfece514efa3eac00b3516fc7457f5ff715e24d2e578b3cf54c30ad2e799b845c56abf22b7097ae00e79509ece61934e00fa10d28f4997ac4a1c82bd9df56c4d52d6e3dd1b7ff9d00aecb5b70d37c28fd5cc08a4fc4484c7411512726768f0e3a56d0af46ffe1fe00ac3115d6ec640238da86162859549ddd995a71f5f5637fc3a497684d100a5f004b1a733a58e301a1561b48fae53353e0a1fe15a73c1ca8df88dd78b3c480f300c9938c91b918f22c0918759d9dc4efe86d6d04807d9f885d72be3a468d82a6006a3b284989a9c2c29c6fca5370a130340326c3845c97577b9c6988f62f294900dffceb89bbbf1ffab48a6dbda84b131ff1b00f2bf2e32f805a9970174583b500cdb9bfddc59eaa5530d9505e767c4224c72f274db16dadc0521eface0b94d2009f9e43e37ddcdc4d78e77b12b2d2ab3e69d7422dc2b21e35974f4c30d6bdf300c39f81b4e2dab25a8343a3fdf734e38ced5b50d34bbc56d1f2dc6feb2baebc008a04c65ec0ac98d1dd34c5e939b3332b1294a8e33e261a73cbb3362a7299f300db35a1e5eaa4658ef1843b2a15947f4f283a6c5c2ce93a78012c53d1f4fdc300366248c0d457b49744b2e70d0b2a32b42b49d31b84387b9bade30ed5e73b0a00047c7420439fabe0a8ee4e66af39491ba31e4f86c85ad3fe429c41c8285b9200696acfe066045b82a56fcb87bcf620c59485e29b0e921da1a9a5ef9db34d830037b088cf8757d1deec8c1c63f2a8a76f1146e63ff8fbe41b80bda976fe8732002b732dea63a9ff29588ca3c0472c14a765a93c9ac5c28b4b4bbd8403ca040f005bcad9f9f9c459dda0574c433fa71057bd33ee81d8c5c12290df52cf85692c00710bc9138c59b7819a6b9371394d383d5e2324ac4cf5b9e28ad31b04ca4dd0004bc6ffe48f59db58ba4319340c2f83c3c7642e663251a35c08cecc28fee1af006e2f9b744fbda8fd457009578b9910864c55b11eed81ec73b9493773ce6b260017abcd716f5d7f02c0096e680e431499ae1c520772fafa58e64380675fdcef00373a54a74eff10e3fffc4be2f5e15826af6f5584c8fb38a24f8c3a4996218f00effc6a0f732212f236bb93a0068e07a21624ca815a681b4a3aac86db6bb8a300a14f182b8e4aa5df41b62834a3be22096729be437a79ecf986d7bba3dc380900eb35d39967217b9646ad20aeca77805a074db67756c213627ae7cbc39a3fd10070443432041e0262c98a7bb90cf597f3d996cf27f952fd509734aecd7c3fa300c166597901c65e71eb531e043d1e3d495c744a49ddfb15776ce90893f5fab100b2f8d31e1f73af643aa91073da1e11b590b01e541ee75c914b32ce2f67f67a003fd5d06ba2d530fc6105c399bc65d3aea1846c5e064eb34eb65d4c28385b9e00a6442f437ea53ab065d885d265dc25c620d2654a622ab4ba7468aa6bed1ce4005b6b73956f85f77ee56b3a1e8f3a011cffaf50ef980427e7ebf148848ff131001336100928cc1849a0bf8ba65c2e16fed4fc1c087f0ea35c83878e953a0d6f0007bca2315a9035bed045cc03cc47a8bde6e85f5325c2a792f560fd8985cd5a00cf4affd3e01143cfa44bfb9282e4103ed8a2750b9a7a37647ce606097c45b5004115424d0fe50f9fa451ae05450bd1c71eb73c2bbb419046bb9295b346824e00e2628945330b9d99ffe31dca09a9f16598cc274c1891a55adcecbe9874a9250038be70dbe1e204c4859f63a5fa928a3e89fe45bb26a6ec7bacfebaba8b1237000cbbc59c0d6b8176d0f8e3d36efd889438315b2ac209cb96e15def610f22930057ad475661953707809eacd8fa6439fba0cdc344072625e2702b7925b669e800dc88bdc5ab4ee19f7a4ad65198a98754d3ba8056ab878fead989ac9896ca1e009013ac98b36e2d548eeac4f9b9512409fc89365509ef25ca4b3d085bf654b200dd632623c619a0377f52828bbd37e2151ec7063f4194e0042cc512b939e22300f566ad1250e74a4ae420de7b10172997d800110ef379b7e15b218ad4e7e81c00eaa8196174bd0ee2c64135f759eee3ddf409c8217fbd8a5634ab7c26574ea0007b06805e7cf605637fdf441182925af2f855079e3b1057f89ef8f0cab3c48900961f5248be54c7526de4407b9a7f13a1a77b9d077acaa686548ad0c078e196003d213e88b9c542a24c380c3e08e5e3342b2c993aad36e0ab5dc83a93fe994a00fdc2a2ff320f7b8454f70cc6fbcda44c2f07bc13273d230d30310c3982c3bd000f8be026bf380040523f98720c3315e447878bbc6bbb1d9c5491a839aacad500b6600434804f7be7c4a1a41c9f209cbf4c356e8624ae5a2055c1aeeb6ab90b00a08a5fa4204cadaf55426d3a357b27d797cc4d7aa15fdccd028557ee3bc6ba00ac6d80a4701ba62ea446561e98b2edbc52135ea4fdedf344bcdd7471d21b7a0014f30eb6ad56aac94032dee17f94b3488f47640fce735797c024af52d9736800dcb7f82d72478c82d59a7b32ef6e24429319ede1e9f193395d99c2b85117d2003a183f1203e976be51a3622314447a1ee1e998c300f6507657634a7fb85ccb002671f80c862a89673cb71a2f112d15c4d8b590da4d99ad5f6d7e7dadfc406e00a5babecbe955e093265c1e5a53d59e27b1e46888050a57d3a8649571cf61d9000f3778321ac908acf3dce51e1ee5631623275544a60bd51bdc12463e904b1f00c441eeaeca3d51162d0c49407b1c9c22e2d592286c0108164e497cb012566d0045838446b7be0d73a0f1605e51a35e6e501827585cc5d30c9f969555147a7e001603d60d7f586f468a257dd6a6771cf8fd9ca60b5f7fff0d2e4f99f061c172007a29e1a31727d853cb53d84cbdde7697fb7b2c8c7c9f8610a507c7b3a1cb000068be7ea1df5a3a62f6a360bcfc72fed6ade7ee9fd6eceda40415820919a52b00c10da180609c0d9b95bd7ebffa32b7084ae3134fdfaa83f69b2755a5a8256d00b96331af74b14e8eb44659c08bfc2cc781c0aed375263de5c19487740e4ac900a5741788998f0c3ce8d8768314e54c75578aaa650115e2bcd68f23b46ca20200c8883ad42e7f45f29547f4cdf5ede3a07e2f779114b4ea13a7a3efbdf0fc6c00fec6bbdbfd42c4f1b587f5b200227ef451bcf9610d3952351571dd0a9a09ae005716e7531c71aaf1b9c19b052cd614e64945027fdc1116ae26c992f9fe398000d58a889f21ad05bfba66872993a014f9d33898cc4f11a0815bd6df31fb44eb003b27076405da54ab958190ed9ab27fb81070a65a79a10ff9eb073047d382ba0088f12e9fc4556f6514758dc0f7b52935f18602d9214f5bcf824d51e1015dc100e3598c04e8d5025d5845f57cdc5a0ad7eb554f1f166c35f0f43fa141ac71520056e58897824ebd2b96c4399ad89aeedd45da773fd0833ab8d0ac0ac4111cf800f5b5e1fbf623a44e4c89caac18d8d11a78ad4f62f6f0c61146fc3ed0fc61e300a310591b899b7cf032dd4d7e2958bb100fcc77ed276bd9b2555cf8341809a70032eb1453c6c87ba162952402348e07719f51c3be2a0109db82616fdd99b87b00f67f59583111bff12523e7bfcdfad7ca300bfd6d65c7421fe2dbf0cd504a3a00e936424b8a7c63cd6b12086b256e79ca6ed067900a026edfb3ef37a7af144c0034ecfb3bc62f42b45e43299e4bca964b75ddf6b1c22263b4c3e49bed87a98300b5b896414eca441bd0b2daffb739e9bdd7c6f84eefc5ea69a48930d631014b00db176b3c3896bed2557aa5621a1c0fdc77cbc1aa990527ccdc2134a76fb4b800e46cc089a288f6f192cddee2ddb84bf5c6d133c5e6e63e2d4a372df6f6c9db00be16e7de3527081efb8a199b17e11445676a14a1bfa743cd4c77a6b9faa73d00dc5c7704997de1f8abe4537845249918f9e807bbfb4b6dbdc653d6499a67d80012015356be4c48287b35ca82c4f6544b33da12a616d08b841b7c0c5242d39100ecb94dbb3cde15ce5fd69b592d2760fd0d403ec047ab1c76ad830c8387362d00b08f6e9e403143d0e97ef8405976cd692f66c8d6c84a6e40705c515659884b00771af9a1f3ef3c77616a9d9d41540e416b83db9bb3e2b75d3c917d3de6ebba00a122a182487de64921e0f9f82674db37765b1ff31dfc943be53da2954b489700395ff91f6d11b792577aa1f4cd53fc78b0dbba37bff1762ebc8709a61eeb6b007de1fa02e0084340083c5b8d790cde11fa341db347ae9ec45f3af68d4f6e6b00b2b4c85f1fc63acc3baee2de829cbc33cc4d0cdd626c458675bb98fe46f7ac0021470cf93ac4a68c551ac214d87738af855a58c18c848882685fbf73aa710f00d0d1051e79891a207edb082901a7ea4f2c18a9b848108ed207625e7cf1153600ca150c325b9a11449f9f4edcf5eca0daa2d83915065bbe26d039ca63ee6929005de6b88da77b347c0e3edfc24cd91b45f48700de27e5dd3a104e92b6f367fb000f4a0acabeca6541239be13cc4832aff587da7bb5fb461fabdf8eae1fb3ba500a75f0016f2d12339a70a4f0b791ce73ca905ebb268fb8b800049086a7fd961006575db8e1999aed0d160c4d12ad408bc85f5c5e580a0597e747cc01d4e852d0063617f3b87bf66ee8f991e11116428e693fe507b52ffaf8e9221d5769c0110002977158e0c33891bcb2847dbc8f0a0dd682ab562b0377d9addfd465d53d36f0029f7f7a814392dbcabacfa7623118e642d4f560bcc3ce77896f9a1feab5a4200f6ae42a99d2734ac9deb71e078f34ba1459f0cec9a6445629439017ac84c8c003198f321e36849c9840d33550c28b2a9208572d053db5c0128e7a9f3a5ab4f000e030029807a45fa1784bc415204b8ea5851a1b49ba1b0f8f731e3645ee96e00fb30d342c0a4b98bf2081228e3c284aa5de1f6e81aaa93c3a7f7df251abf5c008c832a3a631cd7d142e74ead203105a81fe4f4fe171dd22fdb7bd1ef4e3f3c008c3f2b3fd6adaa1ac0f14914b3947d07ae27b07d27651b847a5e96e9920c61008952bce43ae15b2ba104b8099eafef0c0ea67e31a4129a9b5b57153e3b39d600402d8fa334ac6fad7e0142e8c22ec186f9beefec3421dbf6133105d82fe19a004f9ca0f9feb12f7b6775a9297eac5e7c2fc3d3e41ee7842228d5d51fd615b600fab8cc31422c7f542ba2162960e155273532a9c390c719ab9fc92812e8e4c000fa28f39b76bfee90a8e16c961d39efb874ecec1eff1b681beac67d7b3e368a009414e5eadd00d539ff2b2aec631e6bad7db2d939325bf259c9ae0667e23f8900a0c4c2ff4683ba6e8084b35e3c430ed9ee10f951669913e839b7741347a52e00adf1f60a995bae181fbc9a4d8778b3e42495d78d72bcb78fbc88573febe02d0072ba393dc7f12a257597fd2ea9b17fd436d4ed48cadd2dff1d316ab8cc4bb500d116bbc671968fefd7bf6450e77e7d7174c8bee3a0f55312d846a69bc52a9f0074ded2e5e57f0f8bd4c6942ab741208614e84686b4c10beec7a890b49b9ce200c3e2981dbb82b15226add2205b05ab547e9653e8659b6cde6d4034480831cd003c12b0bb94c4769b222aa0a267a214a55bc953306ac38dd23eae1736257c1e0017f7b51992bbe9f8199c74ca29434642517572e377c8110a2b077c482d28fd00a212c30a48fdcde7a3eead86618a4d76087ac440255b0808090d7d833ca56000ac7a879ed81a96a55622187785c94e999ac246902b883600049827dd8f825c00d7d5927a0c634fa2108cae79ab70700810217e8eaa2eb0a98a0a53778e63b1006e5c9a60fc26d3d4e5ab34f9308b9c045c7ffac84015a78c41c48fb409cec4003826dbe97c72b7d18ecdff776b7753438d3472bdaff2c1b5663439949acf4b007f071cf6fad7dc0bb77870d14a26d1827b74faf8b355d444be1304d4ee70b200e5a80357a5e7be0dc5250011ae6ed7cbaf0f593eee770c6b4a0c9a6c14e3c10073943143dcd8f19648ca076dfc9f1d650e6392da20769d2a6f605a3200cd990099085358dd809a5c7c54c130f57525531cbe6cc99daeca3d83463e1326f7d000bccc735f681a9412897f83472fa1face911f90ee86279c31a50ef3d17da47e001f84145e90421515e1aa7784ed3e3cf5755d7886ae9271bb4382ee96ed03cc004ffa0fcd501f23185ae2591a657cb965d63c9cf08c297d797f18e72fa86c0900ab7cc58ce0a6c7ccf60ba9ed9ba205eabecf0116fd21aff233be0a1643b9090054b36305310d44062aa171c9b3206b81ade413c2905da8493ca144d3ba0fb1005c605f0e461d290a7805bba3b990779d4a6dd7f855cc5f1d6ef5869cbd712000a386b2274779a403be1901814305ff339d75ca3532a888ea70c25a5372078500dcda2f1c0a7ff5abf368c7cece1cb5a29109d653fed53d2adb4d223a6a0a9d00072aac1eb3afb5572b8b82960760862bbfe378c37103a46911302f1ea74d5800aa57b1864b43190ff945be6042c61945222b9a2a12567a77563207ab3951a600cf4e45dfbb21662b73fb1b92a9360beb61497a4e0338d0b861393d4630707600c48f4da20f0deec4c9f03e80f151c6c24a3f37d268ca258ccb24a483daefd400271de815d4af6149007d0cc2ecac4f416ab42fa10df1c0514f15362803c5ac005ecc83c4a5b53f9537abb85249c590347ce0cbfd68dd1ab7b8990707002f010020d6401d5eee19e220d43430ffed2a1e320cc1af6da28e26577432ae0056380099030e8b4ffc6008caf95aae2bf1f9559ad08af926fed01c6246f71adf91ab00ceeca89e4d5c3d3452bb667d14dd0f099728f01aeb802a9ef72365c6d3396c009cc29b316b2411354be2c6ecf74dd8e60130bc1276a19d185706888436be0e00b54ae3224afd2c9d571748ecf33378e714a5981e4914f73842753043a047c400c9d2def1b299934fdd2a7ce7c666536e1c934efbf630dc552b30754dd9bcb5000e231a7113c8345347ce1172aa6ad59e8cd2faaf42bc50a666b04210455af600876b16277e219f65b6cf3c45b0bca33c4e8c98de1df56ff216eeb77934fcb300e620d720390fe28ded7b9c2aa0047e1d2f97616fc9377dfd17b884fa14a6de006b3ec8f3db3bf23092ada8138dc6c4f7cda5d34bb030878244a8d20c9731780053e8e1082da049bd1e56f167b6cd5b8c1dbdf5d142108caa6661715c2b4706008a2960935a6c7451a2e28384870bf46bcd2b1982add24893021332996879510090c8c06e33a868257a71a7d1e908d8732dbd863d1570ba09bcdae39051144a0042ec84f3fd9cc396c68ba76ebae2a568c5d9c2ef5255add7ce7fcc85fed89100588076671b20abd42d0f1965dc0e0a02e441713c7e36259b47bc977b0bbf31009c9f2f007623ca2abbad8b3e1b2649afec24600e53beb2847197740d036f0000a0559a2e78e6dbbee720bcad36e89955439a66beffbfebc6a90c218a7e6e170045e3c7d6353906a9780a68037db48e358fcf91a54e13606b3f2439de336ff1000b8ad804b79f195bd71fd3763c1e28a20877c55ed01e4829ef078b18a1df33001b487207833f3819de7f870e99291105371db278af5328b88f59915250dffc008b8b41a7ecc5334a4c27c0caf1e9ce4ad0e411b7c48cbecab3d718eb7ceed10070f350cbd26acdf6c3e8e1ba1ca16c3ae29acda8f35ae814bb271f0ce4df92001ac6c44957089b57c1c3992ca8916e98aad28bf89a7eaa2a74f43082af2d3100cb51d6ea54b9705a221cf6e1abb9e894ae46c727d1847eb594c9cea1a6f02d0047deb350cceaaca8a720fa5fbdad056c29bf992854ed41291113dea700b8480027a4eb43e38c080d1b5c082a5c4c2c8c5fcf22ba51f37754839e11f1f435b200e1f10d8fde9997f114cd36d967c94ee727da72ef5b2b5d2c2b6e08a98d85480038f6eebd7307d0b83f31e4d49f2f00ddc78b9d4ef868478919b1962eceecc8008bf2cec0d18318e2023d9f84cb3bacf847319fe5235f1adf8fe746b6d88f4100cec448c0c2b1cd16f447bb07dba3939581befd216fc77dacffc7e69aa5dd9100c7d27592e986c240ae14431dd7fb2709bfbfa66e980f7632b76a2cff798ebd00edb182aff1c10e36898276f4634c856ce96e8b531b86d852e341d24b2c3617006615f61c6cc58015e879f2d2d5e5be4a7b7d55c016293f960a7709d3f981b100cfd0263b1b477fefe2ca04363039e7efe1719751bfc2336841a67b1fa4727000c365e0c50f2435244d7ef02b8b0a6b11e4a9920e92dbc0d398ddc9c54b95c0004306333a2776697fee621cbccf6edec722da791cbaf26580f9dc5589c7d33000c72abaae3d5c3ccbbd6cb19dc97df03bf8ff8a2f29b054ffbae2fa807e2fce00b169dddb71a37d65243283850e26340cdde73270f25cd697f9e5fb0ea0155000976aed56867d2f5fca587190f92ecfe1ba768bfb67ae65deab2cc84298499200e168014c1daaa4179232567a493ec4339e202ad69175660f74da8036a5461f00f8e56bc2df878b6fafcd883c6aee8fdad9041a57a69ffb6e1b8153afe4254300497d927c87b8627d62585699cced7c3837dd6f1f1b7fa97a2d2f0485c3d6af00cbfdb2225a21d920e9bce0314d2ce5cfc87dd6c95b16777fda2e6379a6d28200f9240ee854bb1f92bedfd7f656eb6d26650e176d19b7abd4a17bf1802591fd0078996be22be2a238dae0e4480314c5e77d49bf13b74852f4823b310d40a1380046905be36f3f8a05accecf41d6bfa7a0393b55dfab6f85dbfe754440acdc60009c73f5dfbfbc7e3fb0dff2813fba27745f3945324c6bea4760a9bdca7d5b3b005eab9cf5494665ab7a18b06ef296f6c731b48091061649f25924db68d8795900a2bfd8f327db9ae7890e74d46edb3e792ab85e11df364a4cf7375b5e2007da0045eb3d774cf785b15ab8593c15f42ba747a4c7d313893626410d69098d0d5100946b74d40db3e2485c2b663513dc97285fb8a543eb304869e3b07481483cc3001b2de037fe53134d185d79e6fa4f9a8c79dea5d5dab84fb02d1568fa78a5fc00b7171e6f55fae0f62627e4bb2b8f90e7bcaaed82260db1eeba20bfb67f89c50073a3c296cbd0ecb7400d2b20cac4286676487dc1b641033bc5250bbb0e269900223ccf9b1ddadf662ac2f88756575ef9d692906d8fa0fc6421c72dc08806b700027c021c3f8950de74f18ce8f09465b483e7749869f37cc0f20a9149a60c4d00796bc546b3e34497c4e684a3949284f5a03d746f3f8633392e489883e5930d0062ca34458def10adec6161a00e9da82d32eda4f2b638f76ce6adc162f44662008ef6d0f8cf6027369f00789e8874c43d1a9d61575c461830c644f41369e0e70040f51a25c71f839ea7dcff934383c7563bedc33c0e07db0932cc539b5a8d4500e3e64184c7f64ba864720877457024a52834a06310fbe8c090d755ac0ff53f00709357ad4bf005f7b0c0d65d9ce7b3239dac8092f42bb2c5fc161026b97609001766ab410025a527de8f9856a4a88fb2e806ba2131dfe2b1d4c363f880f49d005ac23536cb52603523fb1304925b123f6f97467c6cad41da62b0f49aa3a807006c3f67f1c0d326585f746ae7c39ee87494808affbdbc91b7adcb605b09eb8400229f5376049476f253c8c43be70534dbc24825414d79bb8fbb5e8729db84670009c92ab497dec117504408f277df320b510baf78e069ed48a28b0282c57de0006d02a897610eeca8ddfa8c99d2536e91e08d7f8ec61772dfd68463a210a3e300f39bf43b70f15b2f809c0c0b3d6c471b010fad74f5e2a21d5dea4844d9d3a7004e0e17ea2d78669f2e58e5c77144301acd90728fbaeeea4db62a0c753d0d3900a73cec1305a3e1b09d396142d4493134f02aa9426e3dec5152b138b7525a1d0088ab7710b7dd88cefa21ff2d2049829457e576b2c79d3cb5a20dec0726c5e500f7547ec48e8de9e86a310e6da81a93f1eac0ce8f352876f19ab6e9c2e6876e00de314a61ee89d13a1f9efc05cdc8fdae224934c67d552ff5a570ae96c26e7700164077026243791dfc6f2e9138a3a94f5aa246abee4d1e550a35ba27ee28df00efe300feca451dc4e7bf85687c206b04a2431b6813f84884c7f350115847e20087713eb6e819cf014bc6199305472d193ce6f3fa10e04650ec77d2136ed28000f3817fc325c660b163ff285326a096e6cfa52ab68fd797e12c925c007672f800e680ad044edf7ae18a319d536dc5e9e58d45782282f4acc698c460a291a4b500a4cce226300d0c7ead11dbb9f589745ea37c5df117c40a2da1c56c860284ad0030e1ddf7124b2c496cab8b4e885d68d384b7e9af81c3507b4fbc4bd854af2a0031873a9471d13db154f995c4771f3aea58794655ac7ee6d9fabd0934fde8e600b13c7a97fec6039b671d4a17dc715fd4012fd8cd8a9487b100ed27e5858d6f00599bc20fc1f9d4113ea20fac2c3c9d8ac9774887919aa179a8227dc500f0b20084dbd846f6fe4893ef0a8f3b1ae2cff258aab7a79e19286bd6fb5e8bab8cbc00512f01981ea0a45db5033eb2670b8f4c99a383a977e4b59393fcee25ce54860073bb21f6762ec10af582a04ca49e9399f519eba48d1229121b3e01f19ad5e9007df6176034e9f8fb1990f5d61d7f983e49ed2b0aec0d241fa9f50aff0437500017b6dbf87d9572c3429747758a1b1f44ea0ab755d599ba122f4ab9d85d2367006792ec29c91aeb814a6000f2ad7364746a12aafc3298fd04b9d3cbce9d55ef00e29b4a1c0185a3bbf5e729a8274136290152a491e7ec68b1e48879d03ef024002398d4a057e3ee68c4745b8e5add41c90a119364e8159788dab7366abac45c0043c53657c0dc7e5b85c8bac1c4e7350df7a06e11d6142ae800ad028ba3f1110035fc05d251388b27a428f2a29f100894132099a3f84cc54a5cd1ae700c9d9100f6ba9ca0531a1cb787864a05db1048a1032bbb59fc7cbe82ddc8bb12ffa1c000b20cd261bde12282f5a28d219f598b3faa6de3f88a5c726a7e97a0238ddf320081081fae63b1f5c39d95fbb5820d1774de42174c746d233364a93d8e079c7c0015ea3c9a33c19f119596a0d51d636614dfc45c97249bd43047fea567958098006ea9fa1b84e301648c05b927aa6638c77168a975077c1e3a8bd9300dda042200d1db17a8de9cb9dfae4904a31d0bf3b9a5f5e64e8c2bb5582fbfc27537876e005131842fd5612cf587be02776edfb23dddc32012fb0ac0a64d2cba50f3ae0d007bd613d373ffd260bb3bcdfaedb49fe5019d71d6cf56b94d147dace15cb21c00722d3a108885ceaa66525b29c208d7b791b23a3d4a32bf7f6db2523dc99b7a00020197a843d674e27558b6fa4eee5a1b3d7b0e422689a62bf056053f8c33e0003937ffc58f732f0ba027516e4fb11649aec1d933da02cd1b7861e97fc53384008f5599617e81fbc3fda191d6bcd882efdb2874dd5203bbe8b8e5bf9cf60fdf00e15ce5b1675829fa737a4eacceb465ae1d8d36e47a86b70d38da80fb93f752007375ca360b15ad0907cb9028705bcdc8729d0ea22ee08c6bbf905c4d538e2600c3c509b2460aa9ec9def71561fc9523b6f71d6aab1f901cf790a7fe82e4bc9001c2b6d60f8205cf78a85ed0fed6cbc8a6dfbeeea289a1e72bdcc0b36b3864f001a2a041dd946fac3ef5f93f92e6ac0664a5fd444746a702f8d1b92de654caf00673c190a15bdcb2ec1b35b139f1d1ea8180260799ea20081e1bb90ccd8115900f807195f1ffb1554185809048d8a0cf90d53cec597961dc710c889001da4e000224bd92f23c7d5c245134d28242c962afae896728827da71b8c5da6552bc2b0095c527c80e90e9ec13eddcc083a7c696b8bcb2c756144af0b4db75558c98d50041956cf82fb33c8c30b13d107961c3236bcfcd15b4d2c65205a170a0d3eb77001de7334471e4769c6e0ef9a4052102918972433a7009dfebc639f0788c5fad00a4795f067fc5866921386fa367562dadcc5f95e83019e910d914756cc7d8e2006f410b05b038cb1302cf53adaade003aa5f1ad7832bde0f29cb520d9d5ca54006ac1d300aecb908e87b44ac108ba8ba808b808aa30380017671f6457d06e1600bb0f76690c251c5b414380c41a24e9a940228d208cb651faa3eb6613898d2b00641e2983aab388b5455aa6341abf55f91d15a54e8b2455b07acb934c121abd0082a6dba7e125bb919ce6afd0cdd682a19c0d9ddb21bda0e36edd9455d4b2ad00c5eee6a1fceb1c0a902c10f049dd8daccb31988ba0f7f7dc461475334e5b22005f9ca86c5d1c02235253df17435a1585d54f79d8a15b0a4063aae97ac8249500be7a32c187037348ba10bdae522c03e9235ef5e122fdb0e5eec0a88fb854010040da616490ba27ea9c728b85d5e2d6b0ee09a863cca9608e19b19c6ef9d1d40020268ef86c69c306aafe0ef6d2999e218b218c96021780ee6eaea03dd0ed8600796fa4b243389ee0ce031c29043e8494ecdb7beba5b5db4fe8e78b886ce98f004a94572e90b54b8cd8d3003430fa25b651d387bc4ce7a34c702638735738ed00a8df3e42ef32c6601ac7a046730f4c468e1d34b82591b680624f3dcb60a2ba008b7a40142cb24cf2a91b6cf6fb4a67204b03eb4d19d1b77584d564cf2ed87800d43fd641cd86ce06792ed1f091009f72e680e5b33aa2c8166fca864252513400b74b821e49b075e04b462992a5a2c2264b2b02722213c99f48e34280e80996007da383441bcd481e613a860aedc2885c8bf85cf08d67d56ed14106c98fc11e009f948d7204bf869d13b17be572a219a27b6308360bb669751299a64b78900300280471d8e831a57f85dec4763bb4a5333fb960e06037277cd780500dbcd0cd006532d826c48e037cbc8c30720d69744c65488223b78ae902fccf0752c8460f002dec49745ebbcf0208d288c549e276f82bb17b9c78866d4892b3cfd7c2ebe900f8341bd6bbe4e3c6a9600b9b797c627a04708f2a2fe9252ee8f3b85d99c31a00c507ed39c7ee823a0fb5388dab2b85c09f40112e2714588151e412906634d40014c2f694a2b461021ce65fd18aa398830a6d9779804eb44c4bb902aa2149190003186d83cdb6aaf2d2ad5ebaa00ce07cf2a946e353475fe6aad812bff9099000a450cbbe48364ad42e29bb75d77bfd6bacd6bfca6ee7d462142532aa30d3a20049e1f90a16dbcdce69ae5f854f483fa3643920668d49944612a5435559d0a10053f15be586dc46aee842dd8d55f2e64642dbf7d79448c85da12cb805e4bdb80057a85b04f2659c143988e286b437cceefd7744d3604c17bef3676b105727b6002b58f8b84fd7f69850285b9ed113e8a0b05df95ee4ac2ae5ac1c959ed6cf0200739052572ab0b0aa3a7123605b28e3d5fbbe587c3b1fc81f88a8e0ec89f5aa00871325f8c07f06c4178949e3d2d40a6fe448bf0cbcb246bc8a6c23758045ea00766b8f9ecabc276ed604830daa41f9948329bc5b799f68b72c0f939433d351003b46666c7a367eb528d8bcef2d6ffdc9d57d07bcbcdf63e2b8194f94831ab600f9706c35cf01690e995d0937e074fa821985d6604aa5127fd0b7f57ee839990021ce286d39a9e7f6f9238f58fa9c53d9dece7374d7f567cd28a1a266babf460009dc6c05f95d007a01a9d8d83737b8bbdb80041c59d4352518a081ed189b91007b530533e2705c76aaa54a8be959296b23e563b5a20f379f3fee9fec45ba6f00b6c50fafe9f3caca9cee93e3625b3a55be6cddf1a2c1775e1f0ff29658ffea00b563ca6001fce8905971911d2c4013cc154f00613950d81db6e868862e3f7100254b336abc9871a60228bbd0f4605af055a62f7c0684c0e8471acb967096a900f52ce17155d3a7635a6ac45ae79c9eb9332595b8a83c241af3a09c22b8362100e3043e919220bcf4fe6f9da06f4a8ac9c43aea094997fbe9b7d1a2b7e93c880015263d66fbf68a2f6254c6712247dab6a7517f2ad423dcb27877eea4aaddcf007177d7b81be133b498431c1fd79442e4b7bff2e74cac64081eef72fcc71f510072938d75e4247109a15edc562e1f4423bd8339297e8ef9b10ec4c46dd05fdd00e90cf6733b87bebd0dd8e3c4e769bbbeab2697b36f54fde48c866255b2f4a70097779cfa66fe1c6e326838f140edab551ea9ab3f7c0930ef7021063029bcde00a07e3ec10dd3f2ba859ed6d58e3035256c27ae64f8a6bb6ffd06893e687f4800aae559c36694c5f0c947c4eb911ba75185d39ed648de384ebe2cc9991870a700a5348a79e00a572a375c76cc78e88e1dd7d3d1edd569ea3fc61803a6e5c4500008f2497ea7052e3cf9b9adc9e8f47b07f32785185e96fa49534677fa3b4bc400475bc6b4d0eb7361fce69767833cfbc4983ca40563d6e9cd6244caf4c57a4c00720dbf90ed582db5fd650b793e370039ea8c3331e659f6d48c4b48d8896d290046ecea09c73f993922370d1d56c1b0b5f2f06335a66221b65c1298a0935ff0006d2abc3a007206396b64d6358fecbe1597ad26c4f536636564d3285e115b4b00ae696ca858f8f1273eae729f28f470b457cd1d60a4b9f81b6c4d488c42cdc50090a3b92ab04fe790bebc63f8dce8cb1c474bb179437c5bfa733dc13d69287500f134c013912bff4179e667feef10dbf15a319dac6ad2c8053a2356ee02f94b008e416748fadf4c40a21bb47f8102904b0c854bdeb9be41c4a0991f876b79a7001dd7da77ee9597647a0eb8c59bb5c7e1871d66a34bea3ef6cec4815ffdb23200315abdc386097ebb5c978439332531519402d39aae5df9496033772003368a00caba35beb5ac99c4dc7ccbf30d37c100cfeb5643c162006ab7a1d7d4a8700b00fd8198a6b8069a7c907f9f8010540c1919c1c41710429216c8ade8c045c4120083736320ce96d48c4ebe54a1e8574eb391526046ab9bc77a4efa3578c1e6f3000acd7e7e48a3ec51669581d658a309b79860e381535ccc5cdccb40427f8cb600cead15721322b55381924a54323e995ec598b872d39407a714c60de681914600daaccd4b51d3b80095ec4e566e14890dda089462f50982e7123432c54e8cb10025f5d3997177495034738e57d297f5d4f27933ff309fc1e672c007489fe182004b5aefb30542470c676e496cd1b42b20137dae26b27b1c61688d084277e13d0015e2c105797dcd1b3eec64c2c05650b09f6e42521634fec0aea92a8c0a44a300b40ea0a2e744c197e649822e4bb7e30398d68d2fb518710313f094a1a9a3730001ea7cad828423726ba1528a406c551a6498ab0f32eb266f9008a24b83c2ea0043c0538912e8799cae0e07467ccc1de500cddd5d37de67418f21de8185f8ef001d72f87466db7362f38759dcd2a1325beb9e91f168503016037d68a99a52c900a95b5f06afffd9601df9253dfa74aa64201fd49c4a108c48397d72659e9955002060511ed67b9e8b68faac3ff75f14987d8aae7eccb0df3381f4c96e9a06cb00b2d106fd522f5dfcda308a75c2299d01f02d56228500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","rlp":"fa020004ba020000001611aa000000034277ff00ff0001feed56d1420ee27fe2a5e11539680a339a004bb25733b142e13399f2561ee370566c9a7b1533fbb1fd7bf9c45bde68111d004af20972a34d3988eed31121ad9020360a3a5734e146fae3a729592b0badad0051d44b83a40120dd47368416383c686d86796abcb6b031d4f8871ba79164a100c3824e1dce8ba21fe35754a7d0d2c6d8c4c37d526b67ba3057d91a88a7f46f00b27bb885c310ac601f5634f6e9d6f7c5730efbfb2284ad319997e2eb68d65900053e85b0c6ec5c683da7e728615e42578ba96e21f855c1a337537001fd5bc40063bf707e416db4ebdb38c8a48ef86bc47126524c4c1563e03b411a66daeae2003a41cc79ed8e94029745ef64667b2568cddc250aa5105558b276aa3a245a3300dbc71649b84cab6ee79ac1ffae3a4bb0d81a269894310fe1d1e071bdfb89ba00ce1c2821ef0e30551ecd4ab51cf09abeeea314b761f01f891bdf5e3855779e00815e4b708291a6e1d9cc35dc1ef4629a206adec20e717a4a42f5a2354ca4e3008de7ef2ab714c988f8362d082b9bb555c74b30ab8d9cdd3ad89921ca3d3d6c002729f7108589d22820f3a04f0ae347338cc94bf17a0d838fd44eb3c36661d5008a0b5603b5253c210e6fa3c614047e119368c08e405a4343cad97d6b30ecce000a22a3019046205c6aadfeb6459fd091eaee31af225ff8fee6f5543eb37315003b7cab9472a501121a62ca3e870e231649e6e833b58e76f3b5a61f33b367b700dacf4d1d05d68191dff0c47edf65198c20b04834e0b854302b280d0ecce19c00b253300b966636b121034474f4344834723d2b901dff586e74e73fccc5b08300968dbd39417caec3ec90243aa7cd7ef54e00a4cc6362ae7309c8fd19be1fd7009b12420b6a7d2047bd9f7c0e6fe7c29d898d2187d0c0afa970e9506e40d3cb00427f470c7367c4fe07f2dc0afdd7f0646f7968c462417bf8e39be303f235b8004d5f1f1e51c2b027b2f0910a91fb5b50131c423659fec5e833b29a440996bf009c7c8dfeba6eab6132b8b7bcc55f29ef71385d646d5f7a9b058808c1347b63009e8b03adc33e553d98de1e1e9017c3976ac910a662f277e908084c9be6f737007846e4e4067098bec934c724e060c853b36ee1ff2dafb1156a0ccec963895e00188ffee8def41363e0cb485934df99abbc4bcab9800c0a922f4a9f74048aaa00b2a2b5eb5361f4ef50a13f084f336375ee192632e04a7f1781880f71f8865b00db7dfd640158126e7ef64cd14f1bfd12a86eff35ddad3ee6333bd63d9b8e1400065e6d2e82e6b9e9ac59a118c02aa6d67670c0f7e81228300008cf011df911006a0a6e5b4156ba479edd7f4b1c84c734dba7e157ad2162003ae3900913c14d0067db3dbdffa02113812eb1a335c7b6c2eed10c0b5f5799ee6a83fd0b9ee38b0057cbc9951de3f173841428e42e5a45bdd9caac835e32562c844c0198b1370800da9286a62bc6d4fdc3770c33fec9bd93417e8749ce365c93c0a0492de46f12001d14724b9b599a3cc379522667cb7167a9bf597f5822cc48a4819b126d2af2001d60ee6bfa37daa3e7d44c6cd19d423f8f3d7736894fd0e7e5f43386bcfc3d00fc465e9494d92c70a5f84132dc2677303794e32964aa816282c01b896c509000e7d4f24ae15ff8cbabb34e2b2c2e728f904ab2f65ccba24abdd466962b4ce700b9b71fec11ef172ef874bcb13a342141ffa3a6ef8fa85eb621e84f9bfa60680024b1d0d4dcb9ff2164456c91dbfe309d49405dac779ed817c6ed3fec1f6b250081caf3c47793d742560e99cd8fc7ded219f13b150b052d575b86015621a1fd00d128654c6f496dd0d845e85129d1e628703eb688fc701f2edbe890e6cf8f5f00729968509f66b656abfa3edbe0610dbd700fe90e8a2bdf1aab61c5f94f3b6800bc898d258be0ce512c97ccd819f834bc74ee94f09d7f0287515c24fe2d0631001205ab32ec99f3eb997af0f33de1a150d4ea23a12c00f73c8f8b9844e9005d007cc3a76310eec403fb4d078d03e8f299ede73538e7c4f28a6390daef7009c80036e51be5dd4894a96c4c54029c64b4ee0a71b3e26bf2a309b1a4a2e0b259d000b1d8f11a3261287d2784527867e47fe54cc4a1864110b42d2848c859068d870008d721726aae0b412ec7a93580a262de23c17a00dd23f892adf4b886671ed400c268328407a5ce9b6922ec840e6356827781b80b2eb07da3115f72187f0b90004ee876c6daf22b1d9b05b3b0379caf04616a05b5c33ce6143d60741214f837002227369f6842e45357580171b5233f55f5192acc1ed613ab9353579576ba12004ea22883f84a4d9096878942cd429061b465384b3db6b5a8d2a389a2ec956c0078ac6f47c24a06028cb1e3a6fca3582319b39852551627ab05beef36fa408700aa459f8f764c7b4c4a8e95784441b0a5ec12ec71be9e09cbd207bfe4191694005062474217acf247bc3a7b5668f7cd28ed2955a648b4c48672cf91e2c719e3006d35d7226f9773f80598414eb5447ef59c2c7a282af1a9410e6cd023dfedee00422cfb6dd05e38538766a084103f228b9ed6c685fdb983a7ed040dccb02208005816e95e3e90c627c72df1724d603df80a090dd856f7efcb188e931d0e40af00e7376b6bc7eae7c5118662abad7a45e1094566b404551511e2d27da77d6e0b006f1b6a64f2c7d2b24822c5def2d1857ec7bb8832c04e3e6c4bfd071edf38f400e209abfab858d9894f84cd2810d44e537a0a266f1c155e322f997c6dd41f8e000d4e7f79cac70e4eb1e2f86ddd5245f80b797a557e8f4ceea9c5fab7b96891004e42762fb70f8993aa543bdf5c484d5efeb714d0c8cae05fa7b6f13785343f00165e6e023f81e829a8e11ac34cbe4f110c0805e053dfc23afb9bfc7d55b8dc003b61641a11e494ad1f5200ca65bea50ced23682ad6cd7de71be4edc6161d6f00a07d9820d765e8db86a44a861243f03e9c9f6ae651d8e96b06c0073fc6a08d008fb35490de6f5cd2112fbb091ab8299c8e273e69af218af257a70ac4235fc800a9895dc058f34caf30e3db8d7db76486c54187732ba384197c5ba292c8e40d00ee2d0cadec12e228f732aa55bce56917fe5e681fd703733a6acdfc252383bd00df484d1c9c57701588be949013357587b976b0fcc1bd0c195fb50e6fb0661200a9a5f6f57f89775f314cfd41a953577b164689117a0e37c1274ac6c90a080f00758527bdf8c4414530c56116a4364c3bd212485132ad8ba49b104ce9ad45eb008dadf9bdff3367ba111b62af7968a2adb1bcf410f1d2ced305206b3d6fb02e00d137b2457d858f67454c68502903666a2e295a1dc901b77d7c67a4ea525963008d5d377c85f321224c13b8c9e7dbebb4f7bb0a5a54a49eec1c7c42106c034400ff03f702b37e5b5c8a8e8ff27c9ec3765ef48054e33ddfdf35a78d3568ab9b00a8fde32007eff93bcf3c8d0ab8c748d4ee8105c2d5dd396ea8d80cc78fb795002a4939ee2e8f957be8ee06fb0a741b01605483b142c2d1dfe770c2d84a7d9000935c2eb1f4ada8c9f7e95daca0147b4bd896ceaec0005c41c7cc1c82201655009ed0c70c957b359f41c1ec026cc4ec0f3471fbe8f8e969f232fd42e8637ddf0060db89d4cb0546c764cc01f72b30f3b18e13808fae67ab0e888f399c3faebb000817c11e77db5fa3c2e250723752f72614513fceb599bf04496a87b995209d00a0c8d6df62b44d025bb8d9ec848ceced74768d7cb4750299d9a53076e8833200c29f41aad9eb41dbcf7b560810e63d67d9566e161eb30beabd1ea08ad54df900aea612999cee8f3b0b44c930dc75f4f7bfd7e806abe033342434e672682fdd0022075f81636e85adf8bd89708e56db71ea1d8c400260d11f21e9dc3eab376600ca47660f07a25f86d357fe1297aba050f327087d4430bd56bf5152155efa1800ea3bab34998bd5e9805e6c32ad685a9d7363f734fdb9c995577104153b221700211a25bc376ccc14b67ab369b34d19008e7b1d6e85a76b6a1669572273202d00e359dcedd00be5908ae9cc323b504480ec67c6b28d9d4a13a41327a9050eb700293a0e5b5ae26d993b65405970b2aede2d57cc7545687e951e89a1c8372a7f000f2639dc196095c8d5a8793444e201787f8253c00044e324347e2351fb55c200d48d09d41572c319e8eff5ec7708e8073d742897443b37a8bdcc45a721050a00f290c50e6c44cc5be89eee2ba43dd458d5923b132d42149a14fe42fbfc5775005259df4a551fa5eb1893f869203caf11917e2c4c71e7c7bde475f13e99a7450002622eda5c8463d7329fba14036750fbad21241fb9d96878ea1f2412bb2bc500d5266dd616edb4af5e22705381f69c40a380402c16c123979dfd703d8fb88800c2b6e1e193dfc5832c2efd27a13df0eb984139c3488c1fa589e43283999dd300c1248ea7980ea9e1b6e8a325a8bc7f024dd9e406622527606bbeecb58dffa10079e2f26090e63158bd320d87e523fe61e7f3ab7f2e87ee1cf9adb70b8a65c9007eed85a0f9daf95e74c4de92f24d524decdbeab514cf1401593b15af9b7cb600edebfff0a858d2dbe871a4e66991e9a02dc9c9704e5c9a22528cb6c0e60e34008b9ca9dd8e96895edade244620ef5c1009929417f608c3188c506c06c3fa6500d86068ec1d9c56ad673a4a1b19d236e9e11b0a0d62adc205780ea5cfb8213f009f0aebaf5de6d2ff54600cd80ff205cc333ca6e82dd3792d36f637b0dbcb2100bf031f917db10cab423e8b2a6552740d047c3cc3fe5aac8560703fc1abeead000557d9e3820adb1321f3816b76608316c19ccca9a8224b263a06c886b83571000884144990089aadd60b00a9ee3b521b9e101b05c13db13bf9c28c9806d544000982ceff321c0a6bc7a63414faaeb9c59d7cce9cfee7e27ed8e3123d74037d00c01900145d9fa3152480d538a008f270034ea2df2852f3c0b0f2286f665fc400b3b44709034bb1f92dcbd1fe5dd95cbcad937d7fb81673df416fe085b6ed2d00fd05bf10c801a7f7d51a05bd3b6cd8e5f7d06b3105c7a1a366aa18dd9769fe009e1cf63139685338b654cbeecb0e0c4c8eaebe67f65fce257f6e1ea424848f00ff6ea04bae307d83c74ba29df3474b5926535eed2bc1d273227d04fda5365c00d4ad9a5d28342d4560fb813d0c0f11762ae6624470acf2dffdece5bafe19ee006b0f8fe93e87908911106f1f4245c4280bb0a62f3e6864a50e439f717f0d30001702bfb62449ef8bcff3cb60af28255c9e794321114a28c8baf820da78c5fe00c03fc8a86e21924e74af5c52aaed86684c73694b101806cbc5b14accbfe4bf00d2e127745263843ff589b29706bf13638704d7313356e7348c9851d4fe4f1e0011d8db30c9a1ed45651643d2eb7b564d427416d7bedc3023099b153d5d53d7001539a4956934dd315d8e816baa73536e5254ed82542c8071b87d97f5a902ca003a7e7ed0a82d6c4c3004fbcc58e5eb74c7786811b90cba2f9c2abf986aa0d200b047c3526bf6d1832739db5ec43a2299e1f4b6b8b7108e4ddf51002f76a64d00ff7d7fe5aa9d936489ccf307a8a26760afa9a3cec9a65479c492738f41013200fe07ebd67d5eff46c7cdbf24fa3a7d84dd767837ab99a9d0715d1a164a7b68007cf631f8d2517209e8d5dc8a3e131ca3c9e0a7c66dcab8434b3ec354e5ed21003ea1610a42dd223eefb52e88960896ca69180a25ce5167da059f61b3f0ec4100fab62eba9b566dbd7aac2910bccf0eec0b3bb3b5c04462065e3c14bfcadd760047023bc1f7dabd95fa6c6f60aa00cb1b21abf968adbc07767949411af6cf630064fba2f9a83319184062cbe5f07dea0620e0d42fa645157cdc1ef1cfc2ce380058329a59cd8d908acaf8284dd70e3b8ada39a0aa6db1fc9c20ee24b54609440033fcd8ed33a547db9d36f427ba731896d88a424840250f78ef9a074a416df7005cbbcbb15ad219adbde6c2fe5a3ff507936c3c4c95de36cda659afb576299300647beb4f8e59cfcc59be688151c02442f7c4ec5090c1d75b1b672ab07818d9000e8ca52ac9c04ccb96fc5c84ab54ff288a53c4a0c695abaffd0ee23ae8f1c000e64e0c26de76de4a31b0f18bb43b4647b92b934c12425930372cb9964acafe00f47abf61c99c324674446ce4005b575d5189ce85308614e15b245c144ef1b800a375065443600cb967d504ed25e11e3550962b5adf0c5031bfeaeb167f35270064d943ca4964a0f762c3fda16dccdbbf2c7081adacc73fff07a42e7961663100f504512e26b4207186a025fde4f42538976ecab20c46862ce394e72dc71abb0000990e23631d228a7b6b12c1c412ed62864daea2764575b065a069b0b9be0e00fb76f6b645bc1a77fbf8c3d8d3c80090cd5728067ff6d85701c170e118b10c009e6ffbe075e4e93406b3a4f9ded691eeccae9e7a4e737ca06116eee8f402af00299e12368e1ff422f8ee9f1d88fe06931e47a941eb3f2c2ad076d015485747009a3b29e80f14b128c877e8bc63ec0f920a047f670bda43cdb07c126055939d001aa78ae2cd0491578eb50bc138b4d0aa65d463ad755239c5cd7de898ab095200298d6408b05115a841f8b4bc12fe942427e1487e806a5e932768175dc94415002454a831b4dd45d30571f6f035bf292ac608dde8a6f3d4fad941172f5735e0007fd32b1beb7f3b338f107151c3d058440b70080d7006fe9eafa10bed7728bf0057e16c05273741f6531bb89d2229932b9effbad32bd83c858a207a49ee9d3d00b8575e1602c906c98bb113855421633b07424d83ac07f7507e7f802e1c90510079ecf32949b596eeb49900ab124a1d1a1acafa93af5169523c91f808f6a28e00596cfa20b59eeb0bbd464cf14d23eb4dba54a1eaa4fc56d7934178c5421f3d00e4c182996403a6df315cbbe7319975dda0869aec58f4fe7a6649fbc39b43ef003e09d5e3a5a2c6fab26353086161bd421aa2dc5cb2e43232c23a2aa479e3f4008c17e962ec32cbb84af97164591b08d87756e7a85b89f53dba86e73a6c1e40000bb00467bd9969904de85c46d9af14ad263205e384fa6c29161aaa869438b3002c9fb97df0779e3cc80fbd6ba621cf7f75dc52526af5d133cb73589db66923009b4c8907d66e1aac7836115b4ebfe99fed3877ff0db0484018ca739c24af64008556642515ec6f009ee2e6f1e5d7e42342b07391ecdb64e2baab59e1791d440062f6d44da595822dee1a1854b6b316557a215d2774145b31e92d6e771645ba00dc6fa0d39caecb6a906dafc25a697122d0c338e00f844b69da013b1824cac400789295736933ecf510444dacc5278e0b5db201081699e916fe5e61065c2a4e00e1f8769240973717fc7ca685cd820e43800710aef671e03d342069c7217af700d40d4ca1bddef8a55a780918f91af32445233af8c83f72c99dc25a18e2498d006e5d21871307070a54628327ba20e31e902fefcaef6000ce659df2b73141d10010b74584442a0b3c1bc69058ee45c1cad995158ca20a390e9e08fce141042f00bb7e5380359413760e8335a754e0443da3d399544f56629634ded890c1894700c725c7b4ccfce30e60df936e73b10d1b867640fda30254cac0bdbb3f672f4e003319d225ca3df26bc6245e0676ce4bee48961446fcbb93f9abc48f454b3e5a00e75c66b67c65bbd7631610f01c42c4aac72f6fe8de289a034f30265e56a65200db7923e7817f980f53eaa2a4b8187be8bdc65c6c79137561061809afd92fbe009caad0264cc70855f2c0bd66b8069a4e68193a3dc3dd9ea621b58b31afe31300797a3cab42041d51f428d9dedd6051fb0d726cce7faf754771ad9da6fc4e7700cfd17c2a87f1b1df071e87fb9e3f928eef4bbe9b5e37887e99bbe7144711dd002a34b970200325ee2afd15c16e1e2d361ebdf555a86ccba54eed8392e8aebc00d025baf457bf0c912a3c5d0117d7d5b06e64fc51ef3d95b5dfc42aa4e226a600ea2ea124b6150389d7e2b7ab4bea48090183f891bf048c384796eb067b675700f477cc00552ca9984626292865b4c7f21a5a194799285e5db6aa1108c430e600faaad6605339e19190903e48cb54ea44da85e307f2a4a6dc6d60dedde4a18400ac1fb329a9d4004d1e038bbefc656b767b6e7de5a61844ba4fa18bb9d1481600bd1bd68c05974808155cedb8154cafb635d5376108ddd3297aea4e77dce803003bac0814dcb25dbe17c6ba75e5f14549a08d49cd0a7358601e0b74cf188a06007187d687c18ba0d0fbba894edd4b1f72b57c3ad430a718429b39ec7f895492000000a3a7a863da78e83f72db643da3b42ac8838c9632ce2f95ed881446414a0063df23841c8579ddb8f2c0db6194d12b8cc76670a7919cdf8de2a00c48f0bc00fa5cd8d9fc5af1f526c83fd04636f3c42780f50ad0a1d7a84a71e8edee281200202ad0f6dddf699782763ec02bb90f62735127d810f0609f334a638018162500ecdf37abbfcb4610bdd40e323a3e99ad058bc1bdb4fa867f66293485d3618300a121152de9b05c48c90b8afd514f5568cacb5f6969e24b022eadb6b66e69e5003aef5e27601c00f8b0c88c2fcc4b81073eb3ad7d5fb9597596287e495bf4cf00baa738b3dae8de89e8893bcc730df9b498cf51bdf77ca4107952d8e83f0d4800859b35bff99d0b208307507396a7f28c3a879ccbe4fbfb368fa5ae5b98cd1d00efcdb209729238a6fcdec512433782f112a76c72f24d427d2bd78c14f6efa90052778d6b23fd0cd1fc1035ab564574d2ae0e9a51ad597449257c077d97119000b0a12a8d9099bbdf0fc8437095d39eff60e7cdc032d8825af63ebd21713be40009b779265e91b4afeb9ddd4c0b61484adb3c6c30b164028c6d1e2da63b9e5e00c54b6b3d2756f89cb4841a09e8476de0657e6cd2ae89bf28f2bdc9b0430e75007846c923d11526deb829cea5cf8743ce8989c28af37c91922d74c1a86c522c007a02e3108816e68c75085548e1c7bf61b820f92b215864fcefb65cf62123cc00b17220c27fcb512cc93243fd07399e98e5ba08219527de53bffe6640cd7cc600bdd12bdd4521515701f18fd9e28ff7510446f273cad86ae3a98f2e21a6711900959a27edeea98b38f1109792d23c88a37541016b20553e03646e183399e542006884c3023707b44849c49536ae9717cfe28f4f80ab951dbbfc9b1440fd9e0200483914367b47709f48a43bc5be69af95986d39c66955f9876c624284ccea4500c3bdaa9c750196a58556c16b831e3e1405970a1394bdfe6531705b6d2a13d70091624fc3821f138477dbb92008f34c58750d86e3671d9e1043f6c2cd585f06007c712f9a1da5d43e3681a7ece7e7195b4752eb8f26b946c59f8e6abd98b09100d82169c901fe66bbd7e4aff0d7a50d66f4a9c377a9390603deddafc75938da0038fa087f122e0e11598224bb86b1b752cfc20910736095c17cd3ab0e43c6800033c2ffbbcf8fa696a4b34098466a223b9b47c487fc4faf09138b4b2d4708cb0083c3549f3d5edd52f442cc209f609ef002cd6ee22661dbe4be317e5b500bf800cba68885de0a9599f12a470db197070b43d68fd9d0b01871b65523e175c8f00081954ce1145981988fe4a54ce8b8bff331b32480c7d549910fd05e7fd2fd3f00b0f6247b0eeac990b8b7366f36bf5c53bfbbfa84e55aee0fab9615a7dc72a000c8e5af68a6ae75c16aed8c54991914a2a58aff2bc011ca6add8b0000e351fa0091ca6a0026884a361d3b788a4275bb05bd3d2df031b1a25fca45baf8fe5f0e00db79809fa0b05d46e304b676238a0a688004eabb81ceb5d04d4806a654aa030070fd6bc24a7160d888f722e8b155e219f06d33507e8acc7aeaffa07a59e809001e8ad71168e9039a2d55223e2cbdf97500355ea1623fc44034d1bad29215440001f273ef3fefee536fe41a1cf784a8b6131963cb06cd2817c47233ad4cb71900c96b76f6ffd20f257f94dd31e659052ad1997164cd8e9648b05740ac4cb09f003b265915e20c0b09c482eb9642d39257b7ccb82df0e28c67268702dfde1f4200e9eabf3b1abec7b1d60e83c3799c8b605eb24b6a153cedf2db969aefb46a59007e6df7de6fe3168dff0ebcba754bcdd17997b90c36f78feb665cf404a064df00bfe3b561810138e7b2c169b0cb094d7710e6e47fc4ca6b4d4cd4ed41701bc9004593ca6b5564d236981547b43c695637d959bc32399531d57a258a0bcbecc1007137a1deb17f4c1fed10bd2cc8fa42e01c87496a9918cf6fae30f960fb4091005ec60a2d31e2ac2f05223ed10d91cf14b62e2ee7230cb315ca70bb0bcde3d10057f6371680289db1a69265597200e6239731874eb26b1338e14992cd01a4a000b640b2d4bf063d18727ad72bd9d68bd25a379a2ac9f5744f0798fc1787434a00893c98d635c7bfdf660c93b82224e24b9afe413846823f24a60d4ea4c77609009fbd3bfa4542f9fa20393c02b3d44666283d5ef17b5233fa5d117c21eb4e7000418de8359eb28aaf6829f1988001c5461ed9bdb7db2d8a03d8545b3adfa1d400071e1b6273991c4ad7936bba8d52658a8ffb93d469d38b552646ceb523c9b500f3c3a71537b47a7797751a4ae5d1707f4c27e5e93ff778a11e2aa7dd4ea250000882c9234e597710bcb71b741247f3fdb316bb08fa4c13d8aa9bd5af90876b0057056ab9a9d73d4e143bed5e7780c54032695bff78e3da7c66c9587b785f9c00541ff2ce7fb0e4b18b90582f0c2d20e94573a74c62ecd959cd061cd38330390055b64f95c6758f3c67503b099a7f565ff14a8c04546bd76934a40bcbae75b700b5aa2cbcc784a7c5e30972c1ec09ef0cb4007a7314befeb8d2c929fe79bd41002e870ce65370a29a3d01c7949b54adf31d576c58163bcd0f12a466de88e7c400b22356bd5732f25955b56764cf47ad955e496736012cf217632829278f3139004a647a898c0303ebdea80745a39a421fc23636de223135325fba66b9e22bb100bd2fda3778970f410405c6abd1299fdff9d55d8678097ac63f66cc2adfe09e000159415f0fd4bba82bf210d6e7b427e6fb64b8dc13f1754882a2dbb32f998b00e4ddb9929cfc6dbbb1f4a1281412701da452fc635ce8b031686da099e5d97000c68f6fae7d7f01fcd462765aa65875b7c5d425feca92e983550496c38dffe500bc4802f8b19050a72eff3dec640b72ac4005bcbd64023c1e62ccdfc22833e00041c23ea43c6e93ef9ead6fcd4ef746c989c43ebf1b5bb1193b57c9546c129f001509e3a8563f053fa57036bc9857e41ae1e7792fb43c29c9bbf6bd79fd66230013c3e208a07c2eac524def8656a1424caa88689fabaf2ec1f824a026143913005203fa0ab553a9ef3f9be49de6b9d0b3c7cde9f4d153e712a7a590d54454af00fce73f62dca5d4a79ccdf2b0083d87dbb7e0ee78506bf2165c2ede1996b3e5006f9fc915314955765ae4fdfb56f1a7b7a6c14f737bb556e66b31a2a2c390f000b9c93a34177b485cba0ca422136447754a7a58d499fb95df27963cd103183f00f12fca5e1dedee1d77e8aeea3b0c688e63446f6497ad1668f840d7e0ed07a800ef45d493d25992904634d9bc1aa63c237ff047260ae8303a88cb4c2b5208bf00b6413601b31172170032484e1d1fe5f0faebfe1e0b31bb5c803ce9869655ad0012faf96f782ab51ffec48cffba54ef4cb89fc7643dd4001d225169597bd7b2006b106ec951b8e43d38da0d7b34941a165e8ba311e96bd44a23feaebff6fb54006e38b8691872d6f3b159f1bc383cf6b996129995aa65b416d16dd8b3b462b900eace14991d2e58c9cc957e6e043a5cd6cbcd95c9aebf814ca761286e874fde0095465fd9a7951cd56dc6b22e9c403cb2d75c39cb030df1c6f4601fd4d284880060d4eeaec0784514147a0098d28ab9e48f96acdf8e0a8487596405708c05ec0024e4cd593e96fcf663a2e8e7c23f5f3dd054122cf8c3260b2fb58bf93a157e00e6e62c41666e5a5604df019dac6c49c6dd1bbec7e39095a878408069532ed800f1f81b342347e8ecb7cf6b5b31efa39f9c5d8ee38fc127b6adccdad77d0b9e004dbdbe06f5b9e8ec5d6b184a2d81ad5bfd1560a454aead87e20749acc5dd9000a66d992768898e992f99230eff7bd13e1c94a94a92f68795164ab93dcac8fb006480c9413244f089f35e8fb71712cbdb774f46730d4caf317cd7baaf97239100bbbf81c7efbefe5e059067712b065685aabd9f3ee59d76db97110f926e0e7e00c76668cfc7fbf61ce7f1830e28b88ab6b7cb332e3520495e3f2e022b4418f7004a428ecd8a69edc2363f4d7f3da4420f4ccfd00a7132b5d0514e20773a1fc200578a173eeb6d4260508454d53d16b15fa9285ab47a509baa9cf1a4d8e202ab00cd01e3dc22f9d40e0e321cdc3cfacc1178c68bf4baf4105b4f2f0e849f563100dd5c6e526f2788eafe9095fb23288e489f648cc8936182b15d46a69ac9b558009fea6b762ea77e0970f98d7b4db3ce032722a1e543c06d6a6bb8bf57b2f6ea00c34965efec7367bc26f8dc7b66fbe0d053fd87b60002d4554f4437bddd1c3f00d9846f0f11d41aa3581e78a3475380acd2287d68ddea2072950414cc2ad73a0037d45aea2eafd149493bdad64873049aeb5281dfb288d9b17c71c92e9394c7003a31ebab6fde279a59e0cb070782db87fc686e070e9d24bc3da179fba02c1700b8948150e3a74cf4187a1844c8c70dc6bff9a6e8d13916ef85bfea278d9a0600fab6f9946b6f1c40a8a7f270539a05217c205a126ac8624b00ee016bbee0ac00e54537983330f525f7585bbddcf5caac45380d0b10ed3aefb88dc86442d6d3001564fc928365209dc55f13f063c93f2b6ca4a2a9c12cf0753d646c8e10c6bf009f1a783032a447c943eb72cc659116631e9332153640df5ffbf7c6713484e500d66528a6b47d81da6248de0d9830d71143d29153aeabf99782810b7227f3d7003ca6556a08e2e4238c9e75c4f6ddea0e81facb516d62fb44d561983399410a00fe6eda2e5d5e156a628d43d9e65fe67f468517468f1966c5d3d52ef098c34e009e12c2d3ccc20903c41e49f4aa99eb3a9328d7ee6ee12939634447b6bdeb8f00a684e6b618988f36cf99c7166ee1f966c23b1b9a8f3d81e0abf6bdf2b7619500e9322c94c05240e4e04dfc799706f9375d8ccfacce356cb6c3274c09385a3b0054a6348b03dec7f81a756f2a52731bf24846ae0113ac41f17ce2d68f128605004bc73100cf3f62e8dfe51ab3cf93e58111f38f5fb7e324ac2f004f96f65b3b00335c5cfb4abf4c690c9a8babbab1428bd0a5cba47efcfaa882495d9144baa100ffe5a932a71f493a45f08fc9e57a6821a51452b8b03eb66cfe0f7bfb44bf0e00df801178257289abad6ae3b6869ce308cc2b0e39a444f8ced8c55714155d7d00bb62c281ab3ba2e9c228ce1bfb8f98cc0fa7b161f669bd642de113e55e354d00f051b5afac283c1c693f1f1f666fa473fa6ca32274425e8033978ac2c31a53002dc1f90ab914f5365247ffefec103a0082e8e27c2ca1fb7e89c476fe0b6d95005c24b8b25e0db2c87e2d428baab9a926089f372da9e2cb4384cb9bffe2172a006e8145841c788bcc3b24792c579456c619394fb7ad47a7f8dcddc58b01463e003627a67a691df0d0f483c94afb8b93e17cdbe2155ffbfe6bddcdeb6c3e6d9e009397c41cc5e1fce827dcc5a94cedc653c4566489fd094b4997314713bc9c01006666fcf32e0bdd8d6df32357eb102c158e84119483c3f53fd2b62e6c966b5d003a05e5872fce5de6524914c524025da20d45b5eb4dd23b51f176e9fd42b00b0037d72770fb1610166389890e113bc4d1e99901692da05f3161e7103d70e3b4003481c75bcccf5405fd82c145bb668fd060316d09305622d90ca2086941c8cf00ba68f74cf1b0a4f38e96d94ba07840f42b95cdd3da85cf395188a6e1a07dcd0042ae78f5e4923fb5473dabcaba44a4b580fbe77c0b9d012e36a298bd6a3a720062f76d0f6a6687eb985751e0337ffde33b84b06ec7d45027e3160f82690c7100b330b46ca95465f7e409e5a2108666c134737b3db1f0f1d952ed0b0fbef05e00f458525112f8a65321c5c015d5a7ed0e63fd51f8ecc6b14c6262af6043d55100bdd1cb8e142ef3379f3b7749effb8ef673fdf59d730eb062e12e96d65f6e1c004172ad92e5139cea96d9b453bcf38e0f0428b77017e88e88614f518e8c7ce500a827ad889bcc14912bd0c94e9f20dca92747d9347642ebdec2979be2946db200bf6170e7cb7c8d897bf5de8123f1abeee5569560649a5e2b04b0cb2f6a0f9000bfa5cac2a2d860e1b0ba4cfd427b17f7fceb8064cc5d673ab42ed1f46546af003739f258411d848cb8a5d194efe8aacdb5da5c99b6da8acb7f346affd490c3007a45d12083425e4151ad13060777d8eeec438407bfcd100c1f66d0dfbd938c00cc8c64e39ce272cb6ba651135fb54a1bd9d1093e585b83df030e545d29507f005a44e802b80d6f611d1b403c74f42bc299145dce61b056ea95dccfdb44bfe5002fdc0b97a9a9484af8cbab83d3d798d53dc556bbe2a3b187493e853a35245d00c42ff6e6fd5d72a86fe3ccc44d96fcff85eb6b73c65915ec58e9c577eb966f00e78330ddecfcf30d53249308619e22afba0ede2ddf6ed8083b32672d380221006dac89cdcebe31440b76f20ce6796bd5c6627dd35c41ed38a460d12806e5da00665ee6d812a88b77b0ef89f2960da7ef10bca0d045176d57ff819f254d9b4900ba4dd134e3dbfecf932d8b6ac35d9f5965ac6c283546de0ac7e26c44fcbdf800e071ab6e986048878b077d0789721448467a6866fb9bf24188a3b4f0bb4c42008edf4ab450d3ff76269e8f6090c0adf5f4971b6bf943f32608b1f25c027f250080ce78b5b3768c804798a8dcca9d0b7c423a1d29a9a135e07e455532c83168001c03c849d093bd3e140bea7c177e84f0515409494bcd920ae83862fee7dc9800cdfcc95b9c2ac92632eac6177be3aec9b591c09907271730940efd081b009100d2eaeda7c8b659d788fe32abc16f953cecf97b096eb16c5bf1dcbe6821b8a0005ea92edf539a60b97560f0d439533a8c4d6a7752dc155985448d02a54b2071007bc53bd8760f9cdc172d22053724498ec83e3de881e3a3cdca00841f90259b009a451e7734d00484babf4941c40a20b9e593a9c3213a83037853206bc4ebdc00f9a3a7ed6ca032783bc7ddf8ce638aea1cfe615f0a1aeb661271aacdd1c849006ada26b954b80d2860ac6c791b3e71379b5aad63d86bb456001dc704f1339c00bd3370be22c2ab31dd3d7664c88f479e4a5c5ca289450e8fa24aeb1cfcc5a000de743f76f6c5d1584cc00d9159857d047327701c2bc6bf44f52a36545b1a7500e4f282816622b93b548c55f88e67cae4f9c49d4450361b600030d99d2c957e00c066891b9a150087e1f4bdc5c9c3fecc2692f1b914f7c384fb76917e1f8155000f59292a3ebf1f23e5906881d6d07867e1a035e3b8f47772679752a1f17432002785bffb56db1fd912f560526a0fbed9f780c89280827137155f8726aeb38200dc8a14ffc9e3488afff7d7de0e84e228f2b7b2b44b1cf6e3f6d206537abf490081701f06ec57d2e3555640597c13657da2a7d8929697b872e006f9d1e039dc002f576aa23c1f127b51e423e198aadb3907c1e30a24f74fd150a7f33af28b1900b911ae08e08506e1eb59fd9e96d4d8cb1877035054ff26570e651c9978612300ffc1d2fc2c028f0185fba7b31541c93551a8afd6d5cddd9bb9554ebc9051a100384d7075fb8b3575969f382d63536648a9eac2d9f3dafe6c77f92e9f0b457d006ae1681ccb19a2b8b68b312c623ba68d2a5f1a6d0dad8fd0c77aa45dc1db8200feae0a72560811fb3a87edf21dca54cf617ea86c7933dafcecadb90c22b389001fb3c8dc67ad24663ab17fa655be3343126d745569e08ea420c8c877deef92006f3988de8f9d80d3c3972f69dd5212d5958f9ca043714b99b93dd64721e3c800e43e0f06f2a69a2dadc8f8f4995a76bd5ba5403f32f0d0f126b1976d9001ab00e04411d26bfebe83d80d18db055356a5beeec5a0e39aa88fd205dcab63c4ee00ff700224d2f0c39febccacfb2a916d8a7ce21d99413568820259edd2ab1d4200344730bdbccce14066b421f85f7704bfce5e49726f03b9f110a8566810ca88006703fac7e3a371a600bfa6a9500f02cd4df053d6b77a3628eadf8350d4d885003cb0b98c41837096753bedc3594ee21dc721e927717330fc861b3babf8efb3005d66b760840036765742a63d136c3a424651de3456bdda7c5b2e301d8ce957006706c704857df9ea628f702cc46fd5a2a64617b760bd36db8a3d3fec27affc0040e080b531633ecb0f4ef0154932cea9118b563006a7d78c236348e90574980025c1b6b8b15a1d66ac0c924d95b127ebaf2089e1a7253f44b29eb4e95d3c5e00949aa41e615a0e3010b719b3c335dc6202a752b9e2796d06aa6cfb882d7776009e8abb909012d91a69aadc20fe5cb3a304181b92c64c8cdd3d9639047dd26e00aa665a1ee003ca4849f2eccaf987fc95aca99d686c7bf12ebc67daad778c6f002e6797214607380826f6dfc2b51ea36f78ea23c7676ef3bb9bff7ac562f607004b1ef52886ee9bf1befaa5c6036cb4e47b1b22253f9d682a306c4859e5d1be006a1ed95748d23ead1d39612898e5965032b2bdc356e00bc7e87f442125812500a687e3c92c2976440e86f797e7c5ff3463ca832979b7a1d74516c55c2b0c6400666c78e5e939329f25ff6e7e3d90e4cd08edf251f3b6b1104ff9d3374c3a7e00d914424cdd9e428373568d6d176f99d5d8df6a7797aa29e8a1558599429b48006c325170e2100728cf33cd46c054b9fc599d0aae7314fadd8d12c141e1239f00c701b567bf1306571e0a92a99dadf80daa50a8498a7511a4d924bb7a83418600c08fc68699c4f3cc8d636da425cee18aa3814cea9790210389f17598d9d76100f2af949380745ae7265ad9d628526bcece007cff9aea2e40173ced6dc7f63e002384e67ab6ff454efc8ea55a829f024b32898bb8213a2ded2b5a58eb2ebedc002f1f5729b0b1ee3904eca8890b32bbfaa1fc36b4beb0472bc2b393c42b2c500014cc932acf9321682e92e8d334ecaba92cd2bdef4a07f5227a4879e34f2a2600c7c2c6f8c73f9f4dbb48ebaa0bef86396efce39aed077468990a9fed2fa12600c2ef2f076ee7dff0a054425ada0fcc36b6389a5ba07e8afbf62381c6023e18008de67f59e58306ab748a6ce181bf5f0aed4ea5a430139f8862a251151bf3210070a16b08cabf2d08f5866fb365079370bda646a83bb71688fb83bad6efa98000118423bc38c885593e915920c4f025cc2cca9f3faa90cadbc668c3d5d002a800b2acc187c86080d8990fc19f7161b23ce34cacb6117fad3dc65795df117b1600547bb7fa7229eb7e87da79a487be7fdf7648bff7e4765f9f720cf9309a9d2b00f57334068f71b507c99618900585f4f3d0ff57dc11d34b23514922c9292473009e4e6e9cacd6f630031a15a90c13612b9e6137fa270536939014c211da3e88001fb90d48b5b2ceeaa733e6d6b1b266e1b91b132e25341a0d020f8f138c7494000ce0f1893d6f5b8b031c1f2a6e1b7e0a7c2a735cbd881fbdfd0d3edad1b95200cd5dba5492413dcca832ff34311bf4ab9c126eecc75cae24496f03020c4dfb008f62ab55a9b20cfb8164ae3a8d57d511852c8b972d2459303c16f33c8e01cc00d1ae6d0c8bcbeb64372e6b620915ec5ac4c923efdd807cbd22726d522f3b7e003fc64738f31bdd28b29d0a4bfebe5f43ecf3c81a9bad3b79b39c90b9d6647e00c8c840b26c0b9dea2e2f2407489e51a820a0d5f3c0a73ed4ef0a70b24db53700652f208a2fe0f4597e0017fc9269d78e1e787976b17f1729c1788f5b75cb97002d29f2ea824220980a723d860fc2b4837fa47d2f4189f3d3201da9e8802ebc00c53ecfe0c69b59bfebaeea9154f935ce5fb4ee40d6420d45ddb755fab2074d00688308a48275e258af25821606ef2cc12f71ff4ef58d2e7aea7f8a689e928200f45e0266957fd33f0820b249c7cf14c908793bb2d7161fad30b71a3f34265b00e10e1d6cfcaba487459d6b371e911635b457e385638063cc09b3729c9b5d52009ca026fd5203dc83522ba3e99f56727735d677b209b15b631b1267ea315e1300377a63d7b414a5fc69b5dcf6a5d3ecc4fc412d43013bd2260e10eec47d7338009775b62db9be77d7b771b24cfa3236b5f15f86754842c0bed9a28d8d046f23006ef9809a794be2f81a56077bcd887ed1d2f9b59e0cafb3b69555d5619582a1000cacb7ce15be4cffbe4149f796d61bf913209664a0e0cc0dbedd46bceae865006c960728aa8bb7491ca30cbe97616aa3e6c9730a841694afbfd645199608d800dccb8c3abb3bd22806a7d8885c6a1d7c893c314a2687d83cc27de581e608a300ed9d013e7e138063e9630457786d087c15791b0ec7f0701443b66e86abf16100fcf295fbe92b053d811a6695c0757fa5aa1c8f33ef42630f1496ccc2dfc10600bed501e6ecc40f9918bba90d6fc60532019a435530be257a5f6b64fec744fd00d0aed0f91651d598e870d6bf46057bedd4c702d102adc422c761f34b42ff78002db982cf30904b855ed1645cfec919f85c638389a4f416b48af8a765b512f2008a15af1d72df122889fe622675ec5285996135c8ff80bdb78d60ebf3db0f350024ff07ae23285f1e98a16cb2af0da029d21fefde6f9335856d650fc8a8f3e8003b841e4eb64d5ffb30246cfb5972b549ee6f991ef63539df2f4d3c166b074d004a192b643541e55b97afa4a8b60b86df0327471295f7708527855a87552391004f99ceedd2997e4c53c4a01fb2513f9805eb5ffa1300bd01ab4ec270afaa2b00d9e5885b6c924b02e073f98d0715312d671a10379737a346873945a428488100b8eb896fb0feb2e7bec4432d352de170336146940858c5838b659249b493ed00d9a01d91698d4b7b0e2ea69a997daa87606430905eb8e415b209157b2e3fe0004e3d11a609fc79029a64d146fe4b83c1fb8f02c73d75e84047f799879482cd001df17f03b3a5c1beebc3fad7d1e6f24558895a8e9c1b41ca3fd82aa970fdbc00d856050fb77392fb62ab27a580cd1f1defcdfbb03f2c8be35454c915ce107200e0b0b499d040b2895ec524e8cd535cf577bddbe634b57b702ecf3b5ae4b9dc00ebba7c3fb95dca8fb351cf567cdfcb733399ba2d96fecfce0c62c55bad5c6b008eae672aa865a51eaf64f59f86acc50641b73714088f7a6894b57d6058f6a4000243ce2fea334664c71ed1b3d89321bcdfb0c178be16019f3677b3625beacd00363835afc64c388b9836699c92ec4591f2f2a701e70c2b85aeea902f2939a2007771835fc4d0dbe2b5a6cfd40d93d0e1ce3a0f7083dc35aef07a56d452c15600388f7ec91c27ede5d40173fff27aa332b47d6fbce5cdb9469a00beab78afc7005346a0ff7fb7d0ffab01f037ae21941cd1680d622b8c7cebef7764ec7d9e8d0006ef2b7f076ab8d74b76b0b63954738062578aa244e9a7ad5a7bc092a8a42d003cf680a26c16f3ca3bd91a1d3a643c9a0e2976490538f79f1652b492be62810055cccad62c95ca83d77873d825a93dee6a3251ef3c979fc055d044723b641800dbd855ff7ed6790bfa54dde7a07fdf037e64f72032a920d043684b5a335291005a160da2136a2508c3f5dc73d250afdb6c822b79bba4477fcd130863e6787100f87616417346101ddea1865c64f0ebc7c0221359d4d4a3cfe27280ebc873a0001117a6dd890db39e3bc49698b925f8569b314c64bf5abed7e9945e97ac0ca700eeb4435f2bfe268725c0883e1a12ceefe4eaa7129c06aa5ba052d6f055c0790099d0144c608f4f0fa1fd702745cc29790ff508e1e973aee5620676d20089170060f3bd6ca75cb47f9b1df2438ff4f0329cd86cf18cc7d6a4721dd26fbf2cf0000a9d597fd0e23e607eacde8cb42d8be83351573eb1b0e679318f1f674db16400527697ac7e7891e2e8404e8dced70761f0c0ebddc2755bd676ac14037d874a0066bf2726380622b874e8e2caee3b7ed8d6eba8543145531f4fd4c74056302000ffd4875976089d513f63581aeec39c88a30695376e903775df88094d0bf18a002eb7027749e4f615786e461a4400607d26fbeb7c1be48d7804ae5fd4f6127d0078eb8932d153696a8b4baa910fda207629c7f91ac5016547255315117ecedc00a538ff07c4f222122ac24c52fe85492cee229ca925e93caa677110bea948c700407ce0ba8041ba5a91f88057176f24f46b086fb8cdd8e01dfc207f9f0027fc0030c4c0a3e22b43dcd85551156c5adc7411709b23e6877f260610259897e0b300b6ee1cb8566cbdbb318d37a3f652de5583bd799bac974290a86469e6c4f47d0097af5654c1c2c665bba3f1aa05fb556a890de1585b12bdb7228c9ff6f8c4f9001f96ad12d520581cfefd919d719d88e4743d58d3a6611d5365e4bfccfa9f9800c92f961edc3208841ae971641f24a9740945c0e8a2ecace2c0d06c335ba998000f16c49a923abe10a0d7bd7f08e89503d5f15d46694e0cb56ad624f8e13ed900d4db0ecd7061cbe7a631ac4be746b3a4e5513db1d0e986a64829fd143d38ca003cdecbe25f6324cf37e54f6ed8a7c2552db8c1c34fa08d9fa79daafe27d7b100c4a69ecdbd5e8253d6598d85830e66f75b753f721da55310b68c3f8cfaed67003284f11ba4b773bc3f5844469158fdbdff3f1010aae9b4670cb3097c0ac3fe009f40ecb528658284ef2c0dc883c7c1c39d87e0d7c56b082e118dad65e0c4be00085f0aa88bbc383b8e596233d793456b573e8d96fc621db7e21f404e98e6ae006e9bcba14fe090f16020f22947e0e67272fc9ca5d6223b15772d824358ebba00d88502b150a508f992646963ae9e2584daa9ebb72f0db3a514c312649b7b230061965603845ed9daa1186cf51e39df1776b29590fb225049cade327e08f4c100cc11788b02aff016b5832eea302bb7a57696cb451d108e65dedc269f4b194b00ac33e38c9e1605dbb9407dedf0eff7fb4caeab692bdb3cc48a7aaa591737f1001a3b6b516b0a4d1d04cf7ed3ada4aa9482269528a4ca241f93f47566bb572700a04c32563e269cda186bb0723de91c3091a843c351abe3a54137f2b41df595001c881f8916c84b91611ed8158c0a7d03c6965208ce2d6a713fca980119be5b007c0c30f517dd54f463c444dcf2102ac5b7ad3a3beda2263eb9a3853818fafd00b1c6757510fc5bdc3ba535a725dfbe730ac40cf96a26691e0f2948fc6526940079a3e57c730e6c7d1e4f06ef7f6a170378f2ef98752e7603a9ed223dcde85d00725a17e05f5d3351dbe9c76c4fe02113705f91de2a80c000045333970492aa00ede8cba47918a8f1d861a4f334a8da674c27c36b9bd27ca6a0c907aaafffcb00720d93169adedf47bd91b194cc452ae90199bc355244f350a23537c6a6a95e00ea112af39cad964ed8a0bef079a3f40c6984540b8a191860bdeaa09989b8a700ac569acc3666424e3718ac12056f7f1c7ebe6d2727d2b0211098357f3a60bc0078455807848d29ed804032bb02ae926ac994ef9646e54673b5d2fb93ee5a8c00ffeacca73dcb82594f539cc52a1127e8de3a0f1fb7fb40f8cab1804c071ec800e7e11ab3a821bb5e93b7433a6338c4fba478f07da22112a2941e097161e8d000d6ca28caaaabb794960f7d3ec812166424a3c16a7754dcd9d58cafcf941b480086b536a4f0ab0806a2b38ae6f11a47c3016cb01e52910d935e02ea50270cba0054d4a597e6069906ec01b6b677b33cc40fbc8d3cff1401831dcd6c0ab75c2c0058aa6bcb484f3bceb7654941dab7af6be540f179c29e9212e5e6c25c961f37006e47339928f670d77e037a8743977a14ebf780695aa6788f4610805f4d709f00031f0e94d985b2c46b768b48ebb28e12ac9b11c77c4c25da2a78718ec7f1930043bfc0f59c086757a3b5898f06d72a6b7d7ffee224eb5ba3d47b93814509700060b1b7e8c653006ff8cf20320bae40ea9a89b21a6d31e372e9cecfbcc9e24200644cc3b0c214cd6a1c8b31c06e86e3528e47ee24594413723e3d0b018e7e7e001c43f93a7489f149128576256071f437b0a0c7a61e2620441b9b7264e1a8bb003ea4029375463a2ed9e4bd63dedf7d76f63dd229fae0708a218380fed9a2dd00e6454dadef5dffb898b253c0ad8d8db074022d1d77dbf929fbc74edabb6fc600896dda8adfce8292ccad3198deb2916a9c54f17e8a818c9525f56ccfd4e01b0003fb3ec34641fcf002ed52c66f62e5f8dd78b5326c96985bfcf7ff622bb66600d10295d093b9b33a11475fb7a4944bdc1adba6112d6853e24df7b0ebef915700d8bf292d13ad91c6dd83bb3e1dfc9039bb29e3930e60e1eb90c9eed4a2079f0024cd75009d4c25ce5256d79e90876e664384b368df0615e053cc8e5cc1d4200070714ca9a1361e6c37ed261906803a30710f99b7f3cc50e6699b2cef7167c700b85d2980f3d0fdd492ee0519cdddb273ad51b04d610d23626c17a78f3671fa009c26494d4e75bbe6abbb480011c627551efd7a0bb459ccdf685d23c46f74f800b00ef63cd7f4f7117fd1364979772e79737bc5e379561b6e5c7cc62f78d1dc001a0329e0a40b32d3dbd94be89ec42fa5d240aa262310e8dc8ecad98c1f247500c4b0c68abf88285d5b5f8e0b40ded4f21002cf64f4a819bd92b4e24e71ac3300421dbd9d4f5a88edd54799256d6bdd3785e309763706d6cb4563bb4e4a7a11006126efd5760a6be2d9807f5c4601f1bea55e45f8001303b344962d7942647700a70c0ffa5ce359b404ec247b43fc1aea72f08bef06e35c7d67b130c19635a100496bda9638e9f65b19b6547686b7aadc5838fda7040d0b625d4c15e343606200db405b8123a1b200058bc95c8fb0225cecfb57dd39adb8a898a80d121982ba009537687be64255406925140a6454d193bbf9c16167aea7a3396466a30c745b00a0e0f2b4bdea944e38c96f9dab929c0f7a813431cda37a0c0a67fafb02a33e00e55a1e79c4b1a7d38119d18634eb32a2bc4053c5730093b681e5d55404b054004458885b20e29f8c304e1493874f4be42b3a3ea017e8c1b3ff481c22118d18000721b6ee2ccb9f133a23c85735086a5b7b4dfbe9c169d84a833ff56875956300ee6a7928c029d54f9145b5823522fa5522225e25d8867b00ce5fed73c198e000fe7fc7c71d4fc5bbad7e88812c6033162cfd84698b56b08e85c43481c4b9ed0068b53f79ce55ced311aebd207f3eda698c2ba71f69999d9d0bc003cc03880000381f7d522c5e05f3feb7f188c74c5656be992ea1f2c98b023b6e4842e9024e00d194697f72aaf536cceb6d8c5cd55c1bb67a0daa9a561fee541e88943a626f006847c319987a23e425eae53c62f225faa802ffcd210ff5a3c3aa10a982626c007710e6f81158dedbd41dfc96e16682497382e5c497113f84073adfbd06f7200071a4110ec37eea2307915a00ffb56e0f7e9441ecbe830b4e77a19217d38b3400419d53740765fc195c7a0c801a69d9138dac4dcb0bbc585939d4c3c567f48000bf7c4ac768fbc26937a357a1af8470e302e38c1c5ff836dd2a84b7b4734b230030e7523499aa74c32697cfd61f45260749265647b191d529d4082ecaf3328300e3eb3e086751bd2ea260df1d32c3251a6c24829f70d943c812e9b9454c106000b41873db9332b413402a65b95e65d626fce389dfdbc10991d8bcb3f801104a004d30be04ece71d9503a64869e234d6daccc16d520ee70fa07677a6fe70005400c12e597a89ea00cf8bb98b466f1ef060bbe043449221475d76b653f1abe3c2005e0ee243a41a5622a366d979af4d75e29c577675516988329ed3dd11dbe2b3005e4a0cff60d0bb7b39cdb10be9c1438b8e176063eb6fe69e6081f5ecb8f25b004ef35b9fda56730fb0785c6707e902d8796e2997b7a1a542a50f7dd3f7359600becad70b94b020deb40e965ed19a8c74c14ac90eb84df480a2c15e6716a30a00d27537f31ad3a6f5a3138c0b21e65eb053457e1677ac37829b83040ef7512900eab0fb622ada45136ae5bc0e3856a288d1601353cfb8d923ee175741079d4d00baab8bb39f26a1ba9525e7f2a5e4860732c98fd20b0ac38a31de5bb3ce23fa009728e1c2ebe772612db21d1019ec1d72a880328d729a2b4a324cc0f98fc6b100db12debd3b4a573bc317d76d8895d4d9df463da8505d9414935a7b8d67fd4400951efdc332865dc69cfff5acfffd00e72e2e169c36e0f4400e2b877cfec71a00b7bd96426c70ae20d93facf2f63aa54d79cd8cb20f04f7f8ac863aaadae4e7002d274f269e3f117a28afa8743c8ae1f1a0b0c3da28717207be52b9d278b482001d1fa12b175c241c7a3183b31c52385a85934e01f75c97be46ae293047a8060021869dfae9cf9647cffe884e5b9345491d5f810e34e1ee484071b9049fad0300e50a6ba2302787c918e97339d5ba78b2937818bf155ebac6b2fb5d068dd0aa000a247eca84db300f62928bfdacc7963fd44766ccb202c22dcd89530aa09c63002036d49046ffd5c6e17a66ff22daa94df0b149bfc917d56ae8542caaef8c3d00ac19c211965d15eacae35e12f09b17570e480f2d97ccf3b50389bd472bc4cb00e766d27f583eb85ed93bf029632614e674ca7ef887898ceda7fd72af5488b40064f59790d5600f60efd30b0159c844a9693f203e315b44f9f1ae9a15477c1c003a23e7ba519ff17c49ae74cfe3cdd8746b1fa921df770959319bad20afe00f00d3ecce56071de2f504f739fcbd239b36f11f3d2a7b87e40dd4936653ffbd4d0065c5c605ff372624dfb8087d1190fd95df1a101728c2801af7298ebd2d09b9007c65bcbe2415c3ab2e4afc7f7472c6fe35ada45e5dd696e4de16cd350e7c3b005f8c6c64485f9684aaeb2d5ebeb5f15f1a3807957f322d4aaab9785389707900e709ee6e2e8fe77aa5f64894e6fdddbdd4827f2c179e2548fa8e93847c1693006fcf68b24a90386b352cbd82147783446e6d4f718a05bc3e090f1ed92de7ca00241202a758b6c8746804c58717f8badc459bd4bf107ab18580c5e2109b3b4f0018f2030beeb657272552587317901d03ee5e90de4fd5fa01e30270d6454602004804d0f3f2eaa5f24ed6b24bdcdfd0ca717ff4ed06c0d9156069a06d6223a000868240c55a43832ca437543ba5779ec070ccf19f5b117d2f5f78ea89a6f6f2004551e0fb4312d1595c4a362be17434fb23c2cf4e491bcbc666f30a0e67e53e007020dfe10c8a1faa0ea661deddab19344197c3210ec06a383776df43410b8800a2ab6f492096e9a55a6475fe005e7c2ed834f77b876246bf15e13112089b7700840af4469f88dcbd999f36c19f2e4c946d8522c68e3df531d18f1dfe1ef2cb00e1c3878986f2618ea36ee0b176a7da619a9b464f54be8cccf10465f810644900718396bcb6e3bc94c056449ce1238e35edff6c20b3118d6c76d342787bdbd700abbe926aff8b968d77a06e73b7962a55824c9a2e501bb8580e5b788030d97500199ed467bec0ff06fc0ae980875269a8e4189b24363eb650c56da5305cc661002ffda40ac75e6acfa375eea5e8566b656cf0a3e71e1bb602a72900f548bf4e00efc594698f0b7464397a08cc5e054db7256192e6a8d063ce6914d6d43f3e26003dac7c7cfb25d24aebd988a161c3a424969f6a175cd921cc62d25ab5b5dc0900443c71afc2ea27825611737403ea4589494221996f7a7def5e12ed0d26e9db00c5084bd4d09ae051dde2c8e7d81cd5ed36d000f724226cc1b72232bcf1fc1f00d4f29bb3be600708432ba63c84328a543e143c556a76d6e29ec83f6d3360bd000a603583c0856b370a9b5dd0bd6bed07c701db04812cd3413691aba1d0e80400df0dc981b937ef205d21932a4a52e2587278d447f6e1285ac21752fc82a204001d929bae77fb20a82dee53d2596dcc626948f3a7f1cbcceac47c1ca9dfa87c0049676a37122b81143520f2ff0334942470d5132dfcad11ae5c5a0de272ccc000b783cf69e2b00523f3565950e69a90ae8c6bab854be5edfe2e80c5a2a0712d002ca700f41c66cc152857186196f70195d71ee5c5acf55f8b2271cf348b4a8200c6adc11bd964e52d6226aff543c20d66e6adaa232ab80a116b99950cea610600fceab7252095d25209b606075417f5e4e09231d046da9bb738fbae5e7988d200c564ff594cb8e2ccd5655c2b1972c5b8ce79a23dde35a98ca38fdd37545227005c1dedef9814d88e3472cc72671dd6f0470e16438d95d5a32d2865a0f474a50092f11e9e06610874ac574e25743913c85ee3f49b9c447feee39fcebc1935b200774b22a2f6bbec6767ca9d5860428e278b8dfba8b1cae75a191459d8eac82c003364567878ec613e2a97f0ddddcc8c50346518a82a80d819aa0fca015e7b47003f76a2a6269e61461de82742d3edede771157ee9d064d52f7fbad8c5bf0c1b004a8a7dad5892db609b27958fc9bb72722334e684d931b7f2b5dc72e496cab300da33c812642ebaad3cc1ae6afc165ae50921162d4a3a10f1b9f19791e3b331003bc812cb27b3f7a3a6f661d18c3c70ab8d73a0a368ca0497574285e945e9f400babf130c3380aba6f022b8e452c01e5c1a2179336584a3fcaaeb6af4ace182006644c8ea595ba999392ea2dc346ec01e97034677ba8ce6509793d3c0f30daa003b5f49ba0d6448d17e056522e5c1b5a3772bab7915deb498d5dbddded5f86000c48e8725f5d6292261ec6e4ce6f592f00e1034a65ecc8dd16cd8f85bb462d0009012fde946a527b9f04863baad9fa5821168cb8f2ae3bcfbc619b2dbbac2ec00cc757fa9c1856600d19940ff9ffd3684d695419036324ca6492c202fdceefd00938e609408130b0b907ff29a920505fe4abb4d97a1988ec92ae15af976aca700e1df8aaaecd7e6a79f30e1e4027e0e9bb2d3d7f220bf1be466bddd4a5225c800f58511190340ddac2142dcf41d3243354310f05c0de0980444549721f22c700054fed6169ef68c22d07ccbbabe972f0d4c59545856ba4750b3ea4819b90ce4003c442e77d9395c0f1832be33a77ca42d82944195b3bf0174acd982750ac0da00ccb1805184d1636169ea698d36b7b72980a1a63e23092c5c324c93734efed100dcea76617d8c3f6a6d074f7b4681f4a10ef4948ff9cafa630c95f3077b2e0a00962502a16d3add80ae8157905ef4cbbe41359a29f043dd854d84914cf303e400a230343dc3f74c49b219b9d4ed085db62798fe3b9aa7d2a67ce0c06323687000042543a1326010f02ac8293eb803c5e256371caec319fedef126c8c21977ab00e94c7f11da52111082c1300ce85320d03678e6e98abdd0a7ab0821b73dd5970081bf297008440dedb9a9a0f898f589f3e2bb17848c575270ce85c75c731b2200b1a318e782c61fb08e4545f57fcb181836143640d70b567c62908d96c01ea900c1027bad2ef706a0fe60779f8ec597e52374fb53792eacc31f0da3334f069f00d0a5a86da35e6654d4842a4f01c8ec553b3d370ebd98db4364f6165a2f5b3d001229221b4ccde04208b73b818712b1ffd93c8445577fbd79514a123990ec3300ac56e75f3008b9dd71c3e69513ab1fcb3c01a14140c61fccb3d51ede0b46bc00241c9f0991d87db8764f9135dbb50e2742f3bd9eeeb16f4af4d6e30b99a14d00cdcc288bc9f8a8dd2bae2575954a2a2394a2480ced2144bbdf302daaebee05004aa9fb8fff82be4ff359b8a595cf0affc90300d979a1d96170a1ccd2f0cfb2000f3923bf688d6d2ddf6317d9b2f3e68ef35724252b7efbedfdd4586264ed91007b42d9f398471913f43408225f9b15a2512c49d4c8ef4bb50943dfc8726e0400b48a711d4d709ae91d951fff63c93dafa544d2bd1afb07a820e6ecb309572c00e229de36dec4c6e8bafc256f145757d0a4d915fc15e4ea8d19b46e069c05ab0036714073068a7f1138231e7d570bd1729eda9df6bec471785b9bea48ceacee008e0ff30dc7ed0505f45ced29bfce96637d641f6e25cb1abf2e2acfcc41cddf003ee8fe15d69d82de61c0b67328295d37a645037e1cdf4c6656f9278c1bdb4d00ea68aa1eb2c1013d068d641c4b310bfd4ead9dfb7c2cc37c7876631f4b2700008af65173c8e4d04ea7334580e45f4f7b107991965c37753a488881e6f8688f00ef2a8790e36f24ef7ba238cdb669cd3702235b2b33ceb9191b6170500700c6004697eeebd71294e45c855d842de3d3d19c47bf22920c8be7db66d19aa4b82e00902a829e015a384dfb903dcddce6150a5f406b4ba7d3583cf9dc57f32218b800714a83bb9260e976020ac6841aff9bb8f773a925095644347d370fee639dfd008341bd4d1ddb3dae003eb8f558deb5524767a51680431611056fe57ee2a9bd0037dfb476e929024e0a1213881bed894aa6a53a0fd2a08b372044fd89c439760089deb0261481e1b37b110c3033021d9b8e16cee9e8b79e48d714c5422240fe00a20e18ca8a4cd3dc9f04a74ad91256288cac485b3511db486a5a508e6ce04800b3eeae188a438b6f0397e4d1c2295a7e3cab3b5c0ec207c010e21ab43f89d8002ea20f81954f9e8b2e88f4db2a8826eb8bfb485ee72e37f5829a8a1d50563800fe541a5680a0fef03a79a6fba835dea98b166172848a2f4db933135374f61d001ca54f51d21ac6c6a4070a5ac9accacd2517d4decca895fc0f57a4228f4c9f009f368895f79734b9fadb679d4412f6399ce80e033e74f8d8f0355f229b67a500c5bc3a5add3a3b2d14cc0359472ac68181b8583ba91d575ab21010f79aa9420052035c27adbdbed75cf2575a50d83bc90d559d7f65e2edb23e8b4620dd00fd0074fb57328dbc16c70a39a905d1911ea3984652d0e84e7ad7f740a17d4154e700d1adea2c35570a7ca8e3824f3b0e05df637ca823a4daac7a1a55e1152975f5000618d20854b184cb6b1ad322b206f9d3b97f45031b1fcadcf0e381c026518900864e154eb70cf598fd9e643f5c2c04bc2a3254bf82fcb701eba4587744e81d005ee737fa6a615ec3ada5d76e05392b7b0d41ccaf1a100b65e6768f78520e21000668b387e90fd2844431249b9b228c0ac6f6947d253bd1cac2664d0022435800c6ab5acad7630126c59652bf2bce61fd278d8880dd6249c9d58d17615e5b72000182143231932069e805be87e144efeccea4f08180e870a46653c435396be100b3acf9fccec21f93aea9e76f47632a5572880877e9586f6c9c95dd1d786f0e00e878e2f399e7dcf9e04b2335e779974c69676c5d6ff64a0a1076a9c4d8b6570050962f88d389aea78b0893579b444216dbdf92bde40a6022838c707f3da5a7002d572af871d60755b76cdebb949a982b7ac115b5ded5d6866b2eb50485d8cc00c97edefac92c289fbe609b883665ef7c37cf14d31af49bbd99c9a3f868d1770053a1453fdc86e5a57cc59923606d6a9dbee8861673b7339cec5dbbb470fb41004a2e0350c5fc838b0d51745bdd861e9ea5bd694c48a820bfc9d523233bb1ed00c1d693590a350efe5d1e3e357347b1e23083fcf11e35eb502563cf4e1b8441004d4dc142ffcfa8bab708db63ea6ead859c646d736df85a85d459eaf9b2921a00711533712cb54f19603be6c01f209fd9a7186a7b823d9c1f568a5bfcdbfd9f00ae696fc4c185bdb1e66ba794ae9ec92f6e4535f3af0a7a22a49cca14aca7bc009a71546c796a33b1c47233f417f4984c42717007dcbad416f9e4f81f41fd30007d73a6df0347b73de656a537c604b6fa200fa99e6c5d4278e3ab843e9bf33100f659f97c3bfec3ba954779e77f9e1471c285a5af6825b1e880fa35a89a0872003eb7dff85d660b536f206ce8b6b80a0d6cadcfe782f2264112d51852665c4d00cbc2dc5b9c35a62c18264c6d2d135f987e5284aab291f824ba3d54526981660067fdef3ce8af52c43a699f3eed73883df25ddeb82257bf775f044deecb9f1f0059d11af8ba4a55403b50a78435ac70f0bcf691037b43af0bfacb2e8aad44df00e32d5ed979579393bfa45ea535dec1280ddca061e9f2430739c838290e65ed001747c6ba20f7eb820e533962f70cd9ce6e950c3cf7312fb573a1c0edecd9d4002bab4ce767a08745dd90595e99e33706a54fa7df57c2c78bf51edf7574c9b8003ab16ed1817a22d1cf69612dc9b36cc4c00647932e2f1d7a799458444cf52700b6fdcb679101f31bdf58dd2ff2c7bc3c99f0a667d1e0b5df8a489272a3bd0800c99493c2344ebae8a3d0a63d7e2bea1699073b8cb25cd842281d3aee819f7f00c9840dc90461b6c4392b6033c2efec44968c0c516707ed30df09c9acf619af000b52f427d1913ddf26f1032e92856f64a66cfb8406eaa87b6f427b8e7ee1e8006a74be167cc0b70140640a510deb3358f137d2f51058a0f74aff60fe908e990006beef434d88bb252c1e77f3adcf4e7da365be08248da3e03b55655b5580b40079a1ca5f88a277c1341d769e7ce0cb12b33693e23c8e6b19656c2971e337eb00eede0cb046e9c6f4204adefa25df793e964745ad8f19ae2a99e81404595de900baf3fc427ba83ba4b03b3018c892af9e25e1ceaf767bf655f0dc0484f82da10076ff8abbbcc78ee07a7eee0aa9f66955c4e360cf287abfc2233086468c82f4007f8b4554a6656a7640d89b4a2cd0bea32b76f32b17685dd56da76cef3f53d90051443354ac5465d8ff25cadf7c49ac8ffade622ace2566e7cc975a67d397a2008e10a04d5309863cda1bec4e8ccdf5acf4a2b506a10b852dbbd69df83ac75d00367a57bfcaf01cf9e087bbee19b1fe625343d42d6cf139bad834591e8ebf910005593693b30fbeb28f1e5ae099c5367d2fa07676821b0e98ffc207e8bc044100f98011a47b44e156ba0c5f510e08049d7c8b9dab0c00e85b06fb1005951aec00441e9460d62526a388933f0e3170c06dd8ceb296629748209b8a8f9c51edf100c88bfa9a97d27c48aa1a234904eacd51856ca4a39c3b8c3f6189ad40d9c49b00add8fa53ef0a98a62d736bb313f8e9c67f6567805f1648a1b919493011a2df00f53680eea026624b4ea9d252a3d6451894b8770e5786def8ae848249de2dfe009dfe707648b1b81638e9aae20bd55eebff5c55d27d6f9cb1fbec5667d8822e00c4cdf72e0a7af61ad10027474b92cd8f0a7b52889f7bc1c2ba2e38625a0494003825b186a59d0f0c4c6093fd4bc152d92841fbff45357e2bfaeee51712a3720053a2e7c34707d4e38850f664538b00097f35a2df23a483fd66863e0dffb2b500b2442564e2a2ebd966c46d3d44c1fa8bfb8b496344cc89c847cccda13d022b00297700e92c9f0ea0e3116b83f5f6aebc23228c729b72ce8ca282d5c3c7c35900e0eee9beb07b88fa67faddc9978674523817af1f9afbed5318192ec350c9d800f7f801672c34e193f76c086ae736137d8c81d63d1543101c94604d9f49a45c007ae3829720c2edb7a981e71642faaa4b037b2ff398318b1e85a636db55c27000fea67b17d13ca0f5d3e85bbf4a073fdd1f4e267a88dc3c6b7da97f968b3ac500a4e3fb02ca9ee48d94ed03f79df8aa76a4c2f5c95073b42c5319e006656a2a00b55127882886e8b0a87269d4fe70be00f41b63a546a7b8cf1bf224efe4df1500e2c4179298672f302ad79862bc902e80b31c983aa99c69b0eef18febdd9fcd00c42d3b0e1b43a0acf3a1c01bfc3c76df6b95d3e3b1ac8a08cda894fec0fad800fa2151578addfc2e6320f58dd177dfb5977beb20193359f5a6eb8a1be95462000544d9054f4ae2211191543a6aeade0c37457e7ae3ce5981b72041ceadd62d00e5e9235ba7b18abf8c195c764276ae94f56381ddaba5ad6e0efad4437c093400754596f19d50716aefc63cd8a64caa09606b61e361c9d4f390731be2a5a165004114f873b53fb3768a969eec229afc5b3b51ea56068b954a7c388ab32002c1002f1360246be48fc56fba988aa536e48aeed9b54c3445b029c1376de046f19b00664022e412a75c797ee5ba7102b3ff8b7fecabb5d56e339b51ea86e60bd19300820719154201f521b237f894637f8e9a48dca44e10716e906435130066ba82001f55046fbd17fa9ea49b09b63cc9ed23bd4c89f4616c5b27764b409dcb2a5500bd8734ba630c5f928c57934ca6e83334def7024f40bf6edbc25c757cd6adb20083e5f0c295ff9e19f58048b4179e6ecc9bbb12c589119e47016e52dee1a94700f94efc018797b4b708cf4093a343b380fd8b27760417ebe5cca2b062e2b8c9002d65abf0c5be8a86a8d7777a221910af1d93ddd7fc3156b677b7bc8e2531ad0080b456d4e65c1929bcd4ad597b0fda7e170c1481cf839dc17f463c3b0a8f7000212753deda27547dfba3e72b3c1dcee0a5d8e3d3940e10c2ebd91490da46d30049a2ce0f67cc230bd730aa553efc285362b68c995efa27db842de2c56814d200cd1362b3b2b35efc1fbee2a37e6db436f88e857189e0fc05f660266fd7e4a000b6ead8b2d878451d628804dd48f1701b48dee713d51618d8ad952355f61c15005b75e8f2425a6108116f0529eb612259db3b48d39c16f60c207af3b109f14f006a141b21b405cc32514716b700480c41f3a76902fd3b3e5e406d7991d660eb00f0850a47c39f30e781e742b8d20a37b345b6bfbbe2b8abeff8f4eabebd11d40079bcc2be9996e8985f86f9bf0108bea420cbaedc7ac9bd00946a1522510d7100508ce5c294b3462fce47e25d269896f115191ee133ec8a7a88f7e9100650c000a03f338d98d9cc166934bb14357c8d7519458cedbf012c125cf60123f1a09e00652ef87fd28d85191d6ddeb8261eda74a97f221a7692f3885d6972018a932300b891600dcbf3a18a7fee90f1d2a230bbb1a1388f436319f761ceff2cc5d5cc0031e3d4b1d044a348a81fa4c20bfa8cc4ba9c3d4c93db0eee61b3ef7bd71158000dc69d53a5796d18004c570d7aae6a195b11f452995676a2b27e764b1529c400d470ffc4b6f3bf3be07fe5a5bd0673e71166335c39028f594319e1831169f700d8ae9727e9f8954aba2f0ca678fd20ca5078755ff446b229a459e8f23c8b7e0032e49389ef7a18f994d3d4216bc28e1a35cda4297236378bafe7dbb871ad39007022711ba038a8f71367ece46d059bcffcb87f90addbce6e4fb2433816e30c0079bb297fd82a107233bd34222921ca0a466308b78c5560866d89bffc73cc4700e6e1280610cec7979cec678094110498425dd3da8b7c9b84f6bc9ae6bd096500af8248a9472c8571231aa1633070db1846dfd5bd773c86d2ee9631436028210023d6680796a4f440718ac113532391ab6abdfe686e2a7d75f7d9f6c7f147e900711e83bd9722d45d72858e0bbe8244cd5f293abb86165c260c470f1754170e009effaa15c758b34e7562289296094cb9ad33312122f245055555ac9334e7b200eb402f05a2418950291ea6cfb45c297dbbe818cad5478dbff731e4c70cdbb100551f51514e0c1c3093e2923e5313e43be536ddb386d3bc3a3744e39ead8cf400944e8753ca67d3dfb9ae9c23aa1f1004fb47f61efb0159cb6e76b19a8551ef005ba7beb7ac1399e721960c17119827bf63b340741512b76a742542ad675ff200a4047c777d03ef953483bf935b6d3ae17e5794901eb1207f46609ee8ec640a004da1b46d074a71ec5194c57dccb820d89b3727ac88ff7495fc1664509356c600636775d5b4f39b13fa98d84736a5ad5aeef3b62de08e83fe7f8085f3b5bb77009838db2acf9ff47bcbe63ae0a916564bee6beb51381c21bea4fb047944736e009b643d797bbdd562f1af4b85e9d6c13f37470ccfc355b5e36c8fee699e4f520034d140c934c8eca1528fd840bd8e16e1cb60d81e418a299e5de58d9e1494c300608a013b0562d41440475411e92c692c2b1b8caa0ab9632404f085254e712c00f688a23bb2290e5752325ad6d4ccd1ca23f384d28c493c304143d14464b49b0035c0e9d11defadd041b52c0aae0a60a0b81067a8dc1a032d39518f8bc4bffd001ddcca513539b615181bff8542e5c7f9ab47855065de88df9a9db4b136446500589b3ea1b89ad4c6dc21a6341ecfb5438ad060a88cb76dabb42e17f37b0e5900715395548654419df59f82004d68d42ed0b97e3838048f2caa0b674140c11d0052536c0a71cbe4dfb81156bd5ef2defa16c43fb425c22c563fe7a8003af24300402c67b67434c6c28b6d660e14e41ebcea10271cea5970263d3bd069a94a5100d28542b3dead8c66e007a4f2476aa66012f960a2c246516bed3989edd0b3aa0076ad27428fdd9d17ab49157c820c20f42c7ea74dd351cc35ca258d42ea6b3e00163292b6d60a9639e99053433b139aaba9196e2358378df96bf85a2e942c8500f10d102cc2e562794bab0308157c2fd66358b80dc096ab6b4111b030dc730100e07d96b0730e65e88afb4541a63787e602ea8af63803757c3fadd3fcf3008600f6a37221c222016ca4caea7fbdfa2f5ab844bf3e2a3a84d729bb851e4cbb8300ee8605edf018bb7842ba63514ab440f298da06bfb32447404602535322db6500b90fca233cbf2ed2665df9068d96d743d2894fb8cc73c4f76b0168a36da7b60009e485f34c725d5d143ca9a828f13bce7996273a6daa15d1439fdb9adacb18006f87e69e29d2dab17a4efd0321a7158b383f652f095d741f5abf98642174a200ac2b4d6bc14e3407ecb73d2639eca6a67bdfdec867b71b586aa7023f558dce0074dab43aa6cdc975506ec7b7f27b48e0050854b9bad280e8635caec1ad25a800978797d823c8cd591ed44579227b6c305e1cb8d28654b4bdac4c4284a5d04f0011c92ca873b8dbc1b3f5430ea953226f02404354e0d9f01bab291b2225ebcd007e1a0cb2b6d321cde3cbce3db1e732f7c12f819d8bab52ed921c68d71230e20092efc3b168db7fddb48794abe1b31c1da3e6f48b81d10e3544a57b94104083008602377989a11d56474a1173b859e536788b9897c23c18fd6b933c48597fa40076c26808df22f1702c6c36b715ed4cefac76dc0efaaef269215bd57eb9af8f00bb85731141107fae7fe7af3c6ed2fd256cd4bf52b145f69f8b618bfdeb87c1006316228dbb3a09a49fa83c8e0a3cc55422ca82cf440631f35aa83b983d25c6009f6360283fca1a0a2e488ce48ea16b44c7b40201fc5063c9359ba11c47537a0016eb61753fa6350d9f55afc1f58f0b246923a489300b20aa7a447101f8aae100b9942c7e8261c68c17a6c2a9541201796f31b0f3f863e6c02e1c69c0ad5b7700e5eb79da1bee81e08dee0cf603182c996867e97b1a205cd162f19c662ec405001969440093fd990d75ef7cfda3b632add6deaaad0d090efa8889d9ddec11ce00f46ef8394eef1d6450ec1b0fc0b258ee8f0e1a4fde27449fd55fa3db60a36c00d9055f4ffc8c423eadedc327d0edfbba0ea041f8d68d868d7a0b13be1905de00eb5e2ae3230e49ad5cd1caa33d1f771a583269a435ea45b6de9bf38309c06600c73fb3cf216bb7e3c5f8ff5f071de7f7ddfb395602a2c97b988d3d96d0b9d300bd22a90eb0bd788753153bc9ffe3a09f50500897d1aeb4319a1ecf86e5ff1e005f7057c2841ab2b1845317a7189e596a44538ffeeb37220819e937ede2815300513bb921ac9e982f084cffec4f45f7111ee40496bb72b67966dce7974a9509007a16c89f54b874c3e957e71d51947149456a867efd7df4f6fc468f86d4b5eb004e4a24e869d68097d8ca94b871c703b673d698e4445dc644dac7ce7ae887bb00a87c86fa1e0ef30855e6926ed0fc7f3c9d6d9e10b11aab2be731311c846c1800e2c537157ccc017cc714bc72286ee3e783e244a3f31044dbf2167c272f8d5c006b8173c3f528742155f684731babeda1c8662fbe99949272d2ecbc5df06416003421c9d5127854918f6780feab0b307b18271c355d5397110a83000a01facc001b30462052f6ffc0346acb8be1ec7bb8ecb6b451025d6d65d738d04b7aeda400419e2539581aaa283a6f2e7f86903b1ec802853849dbf56ebaedde38fd2cf200885e081405beaad9b1073d647de8c26bda05ead968dc20503442527a60735b006bf2f781e6caeb17ed7f5915ff8f1f6c58093096f74538b9de86bb43d8d69d002c9581906d44ad845efb610423c6bd654124e0766757367321d642d9aa807800dce8e7e77e46414ad3ad64cc5fbcb7319f2d8b770b306cb45eb2925586ec890031aeb01c51d01c20c81e0a10dba2ddc4b69e31299ac02c86e70f0027e40e6900c1701dcedb4706cb948c73a94623fb707d58053492712c1b5fa1b4fbc36500001793b2232cf3050eedeb43d977868bcf5933bd19de31fea79725ce22b323b600eb5768ed4c8c033b34c95105c2a51d03bc07824adb1d9c870b4a25db7b299d00ff2f59cdffddbcf15a2637f2c0bf959e1eecd8d9c9c1d985d4560e72c22b0600eed1ea8a81a6aa475a2e3b987769224a1214c750a580728044eab092c4ee6200ad4d8d68b9fd27bd8c7fcbdc3d8e9ee0ff7e89bceab1df75acffdf13a4d6080018422667e0e74355ef331f3a562851d12657283a919bae2e1845d49416df7a001dc8e1a9e530e4018333cf574df6215f00420429b4d09dbc9d4a2d341b78c700be920ef32374f9ef21cd0d997360fec277384c42814d8ea97fd8e8cb21b96600f0c5f510116c3364189c73ab7a95eea1621867908996ba0509d8b67381f6ce0078ff2802a39c787388e4a6f2a28fe51e7258557f8994ed9dfcb5d8148d5e2800a3c412db2d349681d5d13bbed1ca182d778cd0d707cb49f0659b6d9c9a2b9b00fd9cd12072f5be511ed5eb8fb983b73f0382d4c22cb199ae3871f76074422a006008a0259043631a62926adeaf2bf3b0c6de61717d263659e676cfcba60ca700f763e30b127291d62cad328b53d79e4cc136c79733d03fadf160e133b0316500b42ab275f73f43e0d561fc0095d39e8cb099ad5ba006e6d01a9fd21c1895a400ae544787768a5760e51805346cb0e93361ddd9d7e74e989ba64bb73039b33b00f9850c071662059f993a451e42ac4f9f49eefd5e903c85a0668a73b43bd5ab007bbfbb7a41a2db0e6c09b3513c462235b6b10236df67b2aef6d3b83d74aad400e66c0a457c24f7d0a7221ff681abcc1e3428d45babd3dbaefec99ee726491e0094cb30c62a392351fe1bcf41295f6ee65cef16105a1ac0e6f74e095a107c0100bb7ceaa6eae07251e13ac9f79bd2037b7b0545dfbfd34dfe2fc33a79642bab00bd6dbb2b0ed6963aada906b0c66af2aafedd93f1553cb4d297499c190b3e6800aaee8d5cffc54678054bd9e285f584cb136a5153bff69f246cba07ce34d5ab005a39bf059f378263825d2fa5ba5509217af96a6079140e82abbcc21f16b5bd00c095b5cb518aece91e68a5dd21db43fcde54f70f29ca15590cbf15b8b8828b00ca9fc27ea0988edeb82144eabce5f5301ac0056bf55d35aac7001e6d1df13e005d91e1b010dfa7cf024f8241eca41c1388f7bbacc585e0271479158e8029110036cca3adca3c9e5948f8914109ab1c499929cd2212f2437b8b7f6dbd789b3f00844b8039a5c95ab625cb35ccdaf3e656cc7c672343ae16c53cc8127833b76c0012dcc188644ce2c3c20b063d55a01e816a7b8c5694f49e44d4aeba3c7469e0009ee9e2078c5426e93d14cae9415ab23c431fe303f0d1831bb5ac0f60246802003d780fb066cb0f30e7e46e8f4722e1b6811df389d761674f2d657a56d6e16800f3b156505c0f38e72b52d8cfa078b95ef1ba71108a7a37f4cdc4d6974165820029b7edbbfc7695fc1b6e2ad1c616be239db331621496bd24cdee9c27c0fc9700d2ea349d6b134701cafefcaf1df80d1a30b7fb179a3aedb2957de67e603dec00237fd9c9194c808d58ac4f278f4c8d2722557a31b110138e61232bfcbfdc58001fc6137db54212aceb6805d549b6e4c03a859a9d9db41c24013b7b7160f142007ab2a656eb07c3f5e903ad0ad014e7c43227bad42ed93b96199c901157b2e400d32fa979d87202049d6d70c672e784ac0246872afda31a49304453b7bb526f005e8c2bb58d9bf9679e1ed1c81f352b4fab355b1b64975043b4f7d050bccd5f0053c52fbc431ee830afc8ee8fa2d2e11598b82cc507a24d34269ededc1c17af0022c9aa64fa6fa87a2da54c7b476e2e580678be6e31763a7a72433c82577fc700de095c9c002463e04c907f0e9032e7171bf8abe5b1ef4c230f49b013efcdf100b7d07e20b168fd39fe088902b2baf3925f618a17b15fbf6c76e1f02c26087700ccfe3a6a35209bffc04e50d163b65d62937c80e79ed36d045fdceb12514811005a37d836e4e1a307158c26951ea927acea05330174903e44b374e6a1990bf2005122df82c111cc62d4cb4723607678d78418fb84eb8acd4d389484fa6543ed0067c29ae6b2278c7e9b714b9a8c64d9545e99174612debf9fa7d00f2ccb7d5d00bb1c6c22b50c9631d8dbb0c480c17d13b81ec6e942fab4e9f3ccb6898ce32a00266473877c286053b13cb43c17d8728020843f02874b01dfcd6b7c1e55d78f00a8b3901cdb774e23ccc0e83f620b835c5bac98d38ebffc55584e5b593eade8005c42168f376f51e7836076d9c75a98f7ab533defbefba2754365423219e5aa00f762aa5b4fabc92b6caf0691255c0e8875b9c3b1489383382920eabb3a43ca00516c52524569a6b92eabc2f5f37d56389d7152092102f3285c612ddee3e65200f0ed2ee0ff84339f67a75f9f75597fe19aff0bab067db687295c24ab43b72e0062ddc0ed39a85285b8c5cbe154bc776164d6646c519c02194426cc40338a140087869a33f9cb4a5954dde732884cb79e6de0029f2f49cf4a2a19aa8df9b6d600c0a12119a387313eb71c735c13adac1aff0fcdb135c2d520b34f552a55ce7200665bd18a8bda23199a236e187727a9b8237982fe7561f12e2d4fa440dda66300bfb79b83d6e8542f3cf6856ab1dea8299855642ad4712239c2ca7faa87542e0046a3d2863f427e317fe9d17300c0c338a36ff4f85c401659c7cdc74ff4c20400256c1f6d751059d2212bb3e6b0fe1950a34263e1436934024d77f294feb88a00c5a394e8a2ec013cba82aa55725b21cc027bd84d6b38c29df32d8b6f03c932001dbfb5ed26a6874028a450cd2e16546ee0f35618078d31feaeebf0caf22a8e0025c98b00b89e18b70218e6b5b64db048364fb4e1232dedc17929e7655bdb96009882090b65dfff8f3186d13925faf1859de204c6d5534ce9439ec86bc5ccc100695b249ba165d36244f6c11ab2c2fd0012315f320c1a16651515655b4c78f80086fa51bc7833ebec492c3fe04bf6b32ab4c1aee16dd16a1b9f93db80a4120000c1ef998fe9a3fc69055f186e4b71d8c82d580a22841a2064e29a541491bbf500d111dd5ad4b890dc146c0dfa02ac038946ec852aa13f08a8485a5d7a69183a00583797fa3803ecb6b40fc521ace11b067913a2957f0b6ae8b5a8d419d94e1c00a8d90e419f17593c0ba83baaef28f95c6e381e1f6ea8f4b0631a5d171da53700e10d6f9e738e5769a9a010dd53dda18d7dd2b398bf79cb05ed584de58ce5ce00ad3f83a307b0863f001883277ea45fe5352ede4be383eeab7608f19da275bf0042279829e88f0cbafdfd26828779eefca50d418ef1891d88997af57bc5081100dbc3f465163c85923327ebf4af8aeba8b8b053858f18d14caa2640d8957230007db763ff866c15a0596fa608cb88c3f010a9f432dfb4854b7ca9d4dcbedc8d00ffc623eacd1112d01e7ae5dc3f9676e0e56d5cfbe297302631fdbbf499140000cb5fa52f5c817c765ff74dc4f38419a57630ddfb6aae4c8ae64dd4df950e12003c0ac4bac565d544501d725b3678e8e07d9c13864d8f942201e2aeea23184700d7518100a47edacbb3709347f66b40f4d11fa906b326dda4ebbbf3550d64d700e8f0ef5f8c610cfaccf28a7984dfaf6d55070d00f87df51bdf52363681073e009f4eaab09cc68cf3bac570e8903ccdb0bc669b2e7f58fabbec118ffa82057500b9af549671fed1504cf8717f28e789264cd1c05ec2b1fbe09ba235484883d8004e93217d18f085137b5f394893d95da9467a0c5130aaa9e71f20a40955679b0061f4419912e63a97331b2c7f9f815c796d504d0e8a51956cd882e4daa3ec9700e4d85f272bbfdae0c3ca1848cb737fc0e29a3310f08e683fc1fc060a61b2b500e4c29803b0b3e0101c6710227093f18ffccb6121616e0e8b99b93df9b3191c0070a1a273c32445c3c37933889e821250f3769da8085479f892e6b1b9af474100f48726e2d8afa43487c8603bff9c125e0ef293cc891072babf7c3e0603edf2004b0738af32bc1a300c2471b08e899959de70b7911c5743c08204545189ae7500139ad755bd940a0fc9fdcfd80ddc1d206da2ea78babf64ed1298dff68cea2c00fa0227ca5797f472967b7c446dc2b3ba0c0ee9b446ef2a93368d9b53fee68b00cbc6a81397071f0f4d9b4f88f85c28e091caca704ac0dc3e494b9743b3495000bebde3a8a374c1dc2e37e7acc9f10793539a31e805a47d87d5e55fb4edfce30025aa9c19d1c6f8f074e9007d39b110e301a2815486cf2ed472c54e1fed847300e049799b82f05574bc0691532774a98671fc5c64f9b0ba0b85450020594b3800ac13d8e66b4e9fdd3d56bdbb7b493a5513c5ab7517f7c6478b7969d3dc811f009053afeeb967618d5a8b357c15cb2e372955af220abbd5c848330224a5d5460040bebb840b2ed84b578c5665afe4e8e38bddece3c1c2ef293ab17feaf90cad00f0bef6c5013f0a87a0d5ff774a59b33d05d85667716050a7949bd7901716f800f7a45e1bdb22fa9d8816fa514f4bdaa51e48fba1fd3bfff6a6f0e92fe7291200c78807e5d3f73a102f43df1847bdb3f6200e7215305208c41684b438bae96900a2d6925c9c823e522f1d7e0030689e15558aaf1a11bf5e0371b9a3423c887f0049bbc6850236990453bfd4194d5eacedcaf77af6abd2b436f7ceffe42f72a500dd6cd23db29b47e92c961eb0b1958c1a4b7c2aeb1e53791ea9a8c7377edb9b002c146f9276ba2ce2d1cd5c84b332f5fa3c2c29c6b473464d913f6789904eb70000b32e0f82b75a2001bbf50eabdbad05dba46240e065c099dd686c97369fae00bb0b5caf35205057a1d14a9208b4f5aeb9b923463e5cbd307566a589f82c1300a574b1a6ec7465525b6bb4ef06592cf422557cdd25a120432043652f026c58004fff96269f3fe269c8c07d27e4a8b9abe38946c7449052bd8370422a2e99b600b68628bb5f9935e95e1f4ab88715215b30dbb96447fef74665097163cd4ac6003bc8617db9db513b1332fd7e73e76fa82c03c60f42b52521bf7d2192bbb794002657b9879fdba1cf631f671ad0a2947ef6bc43ce17bc0bd1b6702fc4bbd0eb003f9e03ad75ce93348719c602dcc128499555d3c2bc9daf52a321a88dca226e00bd3af63896b3c1a821a62d2b6b6a4858de0db7d98fa14eb3aab9f8655db1b300e0d7ffc9b73b40598e12d97ef5948fcf00d571324881cd4973e61579167754008ca14205e921846c238d226bd6b3fa71c88e2684849f9fd094d3f26960d1250041ebd0eddf720ab0bbd40285fbe0d3177c65eed3400afe1853d9d8c53d749b00426713abe51b40d1702514bdd48520a43a1ab7c2076279a8cfb9136c2133470059b0f473e5b61f76251005853cc88185c41f1f003c255ce83d82938b64edee001eb9abd77af3dcec6f026d120ea912219ccd086c9bbe7b1c107530e71009bc003559df71020989b0f335ecef26e9ffddff265d55bbd3185d281e1b74db041c007a9059e2ef05873cf2b2d13a1e288982e8b960b6dc3bfb1e30f0ef3fc848bb008893fed201ba592cd1b929f616e188ea4458d70ef521fbd95e6e8d8328db9a00b97c2b11e9b56ce13f598026e176d7b260f96246f2496469475b0472c33c9800a5cd9ad2a79fcfe85a2ecab6399cef714e5a07b2bd1b6d8423f169316f30b300e4ee605f7b550dc8a103edbcd21b563f67965a687f517914b12181920e4d0300667dede0a9284ab60b97fbd250f4d42dedd4f1aa633d33a00b30f0039039d900918048fd7943a48632f392d89987a928f9fae27270e669d4a6a3fba3b51e0100083e4dae65e60343730580d3aaf639aee68a9c0d6865e75303fdd903b820ee00aa82fbd8503022a50ab4e7adc5cadb72fa7fe336c09e27b80a1308f7f035cb00f081095bd53bf25bfe06a3547a408e7007e74b83fbd3638a340619abfe48a300cda808c8b5b60ccb3346b33114f375877b1127c782358126e03d460c6ec3f90037599f33497267b0390e78f7b70c1c4cbec04780adbed1577445f96ec2bbe50032539cfa2fd3edbcb92199ab4abb3fdb144bb75f4256248adc83f676cd81f6001979ad298c06c7ce2cbd466110c3bffed6122db7a7e0302762653f1425a1770008ea072fe3a92faf954ea2d46713d935528825473b09a2b7002117745815c1006f8fe7d446d8d20e194738fe7f815448fc65e806e9006436891980fbcb80a500f282f85b151d7d5e8a5b6bb27c79d3429e56919bdb7482cd4b87e0b5c396ff00d21a4bb60db0b2a7c80260bdf5a29960e0c214e9ca3174c1c3475aabbc835300e12cdb055e327e04b23d335a61cbe7901aa420f1bb1aaaa78ae49bae0496fe002ecfa52f42611a8b440f0e3fe92876e730fbf3e0bf2c33bc1b3eaac20a5b5d002319f0d7b94260eee66a148f5102e25c8037a4d28df4514a5330b6d916069f0026c98ceee20bb52214b7aeff0cc199be4129d22478b022fcf3c3378cb1e07a00a05bf2e0b14c9289a912d1d42d4c880c0ab45d587c59d185585d4d8fe7e1570034d7101b4321a5d680ad8014fb2762c202378835571424c2a85343398c70210039fd5805b8651a39fc8aeb993258cf940fc7936478ceca2ea8dbed628a922a006b91c2e220608e40579786461aece154447a219a0afc6a0f2fa3b5f74fd24a003875f13b8cffe8e4684323c86a4820e7c1b820fbcdfa1f5e4f5a50ab8ad4f30015091383364e379aaf3968fab60a85f80626b1954c872c34c87842a91da861003ed30245fa845880eb217016bace34660a977d11c124d0f6eee50350553a1c00d569d98c67dc2b4ec6afe577c2b970d1092c65c721b258622e69a623365582007ddafdd9a35280ef7ebf54aa3b138fd2cdd39d5be8d63547e52905ac98fdcc0040e4971a0511199a543e756d053dad063bf90054b28ce202930ef1db91095300f50da75cc46dceb7cf75a09bb4eab2632b5bca5a5302ffe22e6c33e168ccab000683d06a24b24e79d15164f2e18a40ff050947cce7abcd053e3e368be70fee004873befb8696df9403cc513402d28814da8b9095db2846c0e6b124814f392200bfa7479ae9788f0d49c8ff5134bbd1617c3eed295264337290fc9c750e610a0099adc60aa032d31ed7d6e2b0280f9603344635297e34629a8781e085072c3100e29ba18d53994b118d706473cdf522d27f574487df2075c750e1aca5c6efcb00541b94176ebd7f00ddf6d6f06d05c3d673c75514c5ed6c5851f5bd5c028db100234e77deaab208af207d5f734f556cf0a28ef24a7edef0a5df463fed36799e00879044771c3260601e56c4ef47989d55c9ceb5a207eab1b2922c6442b9be0600c11ce46db9ed52fff5f5d3fdd93aa1f6ecd6574ed91747f98fc4a0ba22f27d00949765af0b8bbf4665307c409f04744e05734c7f0766a17578f94b828109730020ccb4c147a737cf23408e598a2cfb44092a803aefebc4f9441e3260bfb25100aa3b8768d2e48d4042747b9454b35725645b78e48143c5d80a93f2815b20ee00c4eafa6b1ff7827a52c541ab5435daab763b0eb47eea2ca16caccd4198d0ab000057530cf078a3b6cf4b2f19ba82b25dfedcacb4d0dac685c73b42841f241a00758d97bcf8043ade451a394ccc89b491cfce4ebc4b5987ed7310395f798f9e001c23f15bf38898548ba2f5f9657e7e94b373f16cb3930ce8f137628bcaee9900d80bb48a9d1486f9a2b7f5a60ca89c55ca0727c22f9bf3e09a1cc1a7458f5300f2d5032bbf5f439ed30629c6acc8e3d19da8efd52599e37b2f8b776dd360b600633a3682573e90602a5af7ab124ef0d7d1b456865d4851fcab37234c7ac99e00a12819e40db233508a200efc47275225afca5ac53d683ebae0ad7da89bcee90062acbb45061247f83152ca0c291ee4989e3ab9d4a1369ec4a1c895f0d840b300d9ebb4546f63f76cb76a303c9e825d2d9262e1e76d62719978e8d0a538e92300dfb8ebdfc414f7f90d80ecb3c1c8f86ef77fc43fc4447a663a8898c0c994d300d74a55e62263aab6b910d2072d87eabd9a5f88e93dd6ed848310298594daf800a3901a9af7aa9ea3d74a4b6cf74c6ee2e3a613ef0c7fb2e110b18000ece18f00b035c49408f700d605f52d063d18269bd5278d2e6c378c184b3b2e1ad61538001a473751863be97f90ff9036565deeedaf88e93849908d22c8cc33408460120076bf48b06c1d56afe9fd4a8f01f6738d68c695b64727b64cf22cddea72f51c00c8e46e22b9f8d7a4bf1040cd93a528f80046df3dadb5a5742e13ec8fcb571200d3499d8a8bca921b8db7855edfa018bc1073ac0f9f7e54ad1c8e0ccea76b57006027a3106cf7a8317ed64b8b0551da9115189e4496201d01a95e32bd7ee2990056c9b2d8f06e730f4ed137cc476131eeec90b1e706d0c579f3c8f983b44d9100f48de35578a1a640e17d388bad434b6d4972eb3b466d722142ad27fa23086200035e11d1d6eba14d0f7f1a581b7f10a029e0308e4915938b39782de580492e00ba83321c60845cf486eb03c4d16b36f62c18144d4a036d1adbf6711e4a044500888070bf3a134eab6f4eed342563c8a6e4a5e399bd7f8e771998a6b8f6511800b66944a4983f06a2dfb6acab0325c6b8ce933d4300f6862f79ed48d44cc42d007bad7f53eb59d84326984ffd372d191ed24bb0e6fda43c1a409150478f4d7e0045a5a7574a0680fc12ebde2d6c18ea0f221e61469eeebb2d2bc8dc1ef4f44900d73f31bf085bbec952bbec8c4b5b48715452f866b9292a17e78086687b6dfe00aae829ccb5e98d946d90648c66c3101c38bb0f93f108c35321d9837fd7966200078f1fb575374d8bad24a753f9a8c7b40e11df8ee0edaf4765cec82121de9300026711fb74e7215e7a818ae9b956f17b43a3a7ab98a2124c8298571345801800ff3c604fa4070adfab11f22ff3d520096a87e67a59884243a4fafc2c48604d006452b3f997394e05c8d424ca431e8f92b298662b5b84fa36fb2e46d8557c0700476714a8839e89f254ce2b9581f120fe58db17700d8a9762eb5c491589d2e6002715c40f1850cd27de78063b163d7b1a5ea0f1576d1e6c7f26ed750c7c0a0900fe2d66cc59660ebdf6c9e1f0c93434952eb0d4aed7b6c1cd9f82490a269d3d0098d5608a5fb91f03e12fc15b9057d527ab56bc5ca32f66c75dcee1dd693d80002a0eae4e45d859f4a5d67a0afda88c656bfe4ab7c3bb22089d06d0b909e8250087f929ce52eef2bbe3e3f0fc24149c48367bf856b45a501d135965531bed7600ee6add214eb42a4cbdd72b0138fc213e48eaad5b470e4205f86a2e8ef0910600862983b50f32b2973ccbca22e0d253ca041e56a86afa07b3e62c173c4fb4e200ecad35f37b2b436197917a0108a8b76106ef4684ca5c6a3bb30e78b3695c2e007a28e5a6c2a64f7c9d0a99ea2c77008b867c45772b6e9d6f94010a8f898de9009c0f0f0b905d5ca5d39c69682e614ec2a633fad3695316acc50b1c949ab2e50028287b6067b85d2a146d1519f8b382f98141d021074aed353f2fa54f1e4eda002af33fb23d9554147431079be702b4bd04dcb7cd57dea68317b72de7dce55200919b5c998e86b5b20cae71ad1a8138d49972bdd4dc738a2aa8e9d06799a8fe005a3c32f0c9bcc078315dad2859ed7a6256ea98a596f3584a2da9f3e8f08d22008e44e248c65bc2e0a86e177e4d2bbe0d254c521c31c783fa8bf25a9075c98c002771b99b777d9079c0a4be4143d03afa3735b4ac32a04fe1a0b1d2cf6aaa540060f4425e3538f6f54918e2c4e9eb4bc2ffcb3ba60da395334df09c205d7c2a0084754690e40b93e4388cb4db710ec6a38e8e29ecb2d0b37db69779a2748a7b0080b3a85366128b91f9415fe169e6dc51ac924d60edec9705ffe4b41051ede900280007e139b4d216fb006a237201d60f71665f66dba2abedb2f908cc89eadc002d16aebac7cc45e8778a0fd85c6a07e3d8ff7104be6a730cb9c15b8c23b5a2003c8ad83c2a070053d5c4bdfaa649119d91fe97588e7c3310ba4bc7d4ba7a350043965ca7da30109eb325015a246df49ab1ad83446366388d3c3d44a1b27014002af51f67c372ae9798a3b02d76ee238a1dc9599e76cda44de1bcf4c8964c92006dd21ec66f875e56ceaf43b07b7cbe30d3b8779a7dd2af949d32dd9de63fb200227343ca76829fc73987a2a5a52496a781abea7c686f1a5280ce09d14d79f600e77bce4ed0d9b69483056a227527e2b5fa4f1450d15955b41498fe83acee6b00a3f09f52a8eb9868dd507eb4a65503d26f61b0c5b9f0552850acf69241f63e008c8d43e2604830d8066e6c25f68acc09e5437bec6a5d8b4976912271ab134200d2f7bbaa1b41c3454f2ae137caf6caf28a680f02a1fbd45f0ba1da7c480185000baa994a3240caf4b7fc3f5ca243373e32902140e8e0906b20c54481d7de3000bfc95bc0e72a29f4c9cef43acd7f4babd8cc5de8162621e172bd92aefdedf7004445683bfc5b9d847907b7442d77776b180e7fd90a984ea5f8d19a56d2d20d00eaf9aa43877c376554e22c202b5b13e5b01ff753475966e281da5deaa3144e00a4808c0c5c4e42c4907a7c631506a499ad94b9b0d10115cc1f54930085d6e700e56901e9916a9d7abed3a686c237b7520d512413e6ca4c173349b0770997670007969934760941cd30b87859300f84b5c08ea0bef49a1d7a98f7bfdaebd862001923cf7bdad045a9a1951117e91b8520f4e95935e21c10446bd42f19d1ab280082109118f0da06aa2919788e28b345837d9fab83f0ec229bdab7e3ef873ae200034151fe34a0f2181c7c4f3091680edc50962b4749e26c4a4c4fa1c448dfff00c7be0b3e77ef5b3420192f711224494cb2e2abefec2d282db38f1a5c46c8dd00ef972742e893cbcb8ddd0d489a1c40416c6e53e592073b9c0c98fa1a600d460053306924a2f2cf421822a46aaede8db116c4712633a6202b38b09d4222806800dcf43107e74c8becbf506093e56d3487eaaf16217fb0b3b16b67051cd44dd100c28dd3cc703e99cb016ccc7882efaca7f170e1a02f4f3c14012995fe8ccc7400e41f7a4b7e6089fa9ff219a33215609d668db202e69533b0e2ce9472bb650300987db09877abc5eea1d91f5f4def67137e3420f5f9f8d2ce37db80885e63ac005da4d98b2d58bed6ee1f6ec66585fe220ad5fc37e4fba7397e3c7149354bf600bf5c7220eede29e849f50c73a42fc4f43faf97cac1b0f93fc6e3109135e0dc0028f37a98b1871154d9a326428509ebcad4e28a6eb394b052862ed1dc265052009508de9dc5dc836cb6556bcc868d806a07c381cebf1f48932b70abffbb9db900544b5b5a5b7904fb6a40e798c7a4ebfcea20febe38f4fd3edcc8bca8ac45000028f83d43346b937072d5b15d6e24f506fb214d16ae8d5228aa20c99e7bc7fa008ff7912ad16dda451f91f55cdc781e8c314f3a947dc28fbc3a10d79110848400906b9aba142380817a639577561810832ccb4cf53936f7d3618df72e869235004a8e3122a95c311b8412395bf8c7f9beeb70a49f4a6226cf19ee4e31c8587400b9cd3f9f6551151d5e1bb8089e4e3bada8c92d9b8f109eb1be6f6e30cb237b00367a0e02b45db1580b250fd0cb3cc4c5bce7d8d5c9378b6bf8179dab9847610034793cc98f17cd7aa343052f297e6d1d902f45b1d8d0448cbac6360ded2c3600eb44f9bdccddf10cbc32aabb910baccc731677568d384172583cc7a41200dc00ea34dee172dbe767487f099691605390d99530ac8c5d295f2de9ace6c4f1ee00f95b8340b5e2c86930fb908eabe2676ad66c1b85420a13c93ca628e259eaef003931ff0c67a8351e1c7bdf49b80c7634e7106fd9e0e456fd4396fbff7dbc1300c902f3f65ccde219c5c962526fe0939fb01d0e2f96051a56852a11ad00c00c0028538ce109f8d254a9ebb8dc9247a062157dd20dfdbec6b63018afcb25837000be7f486c7b8c2be90c0ab297a30c4b9d1857ee28be1943641d0079c3226544000ea2381ce1b31bff0fdb348e9c133488918a1a8db5e23ff8264fb3677ec35d007ddcd36736b42c7e244fff9618bf8d0c6ab2cc04d08c198ae6632bd48d8bf10086f071ad705b5f02f0a1c40fbedd2d547046886ccd8b420601e3a8c592d40c0020eaa5c0f8d6ed05de99dba852deed9da4f195e1693acc0e6af2ddaaab2c64003bd3702907212640b2bbd332a04aa96ba5cd9bc08e9be0b44f290e0abccf60006f51dabfff5f2f0d495b353356fb8d360758f6d5fa4723282dea778dbcf8d800c2ce71cb22681e38fe00aceb938f0702f94ca3ad4d1ca0985b9cd534f59ed00029db68d3438a8f27cc3002cd386d803f078a9a530a97fbc3a9f16850264688003dea46b041bfb11149eb77ce6dcf0d51f38b25317e1bbfe3cb58fafcbf0fb100629f5adb4b7162cf17a59d848b17bf069e2573d2eb577a8ae93cf0617af64c00f6c5c1348105f828997e61de4cfdf5d854480762d7c4def811ff18cf0cc091009226ae4a0d34822f3ab1991b58c759f0e91c6ee4762401ee3f51a1bc9914d6002ad08057c361fb18c3196795d10e39e618eac769418541075caca92b396a72008d5b93ca58a690529f2bb2f93b9335a603b026a0d11be969b455f4f34204b700af1ea90837d36b37f167c9ac104e502b4af03fd6b4a74b23c4aa970c169c6b00266905fb3e3549e3c0efbc005317498c9a41269817fd4322178afd7282c1910035a6aeb04fb23df619e70df830e6a9924d8e9ddb2dc623b04826ee9b5094450068459e47e0d04b7b539a833220ad3f9c49997a33631bea98436fb9a12532a80078e788a59add53546c4e3a09eb8734c875e855611cf17f45db8aa5ce4f82ba00f308de1cf83d2d3b11a73b465ac7d0fa98c23827e9a9bf6f8dddc28df94b5b00792acb25d0f2dbf010f9496efa1e24bc260e14ca9ebe08a892d8215a9b401800b24372fb54330dd6c6725615f095eb879e65cf7c13821b63be27b0904eeb930097d29cbfee8943cf50450e0377ddffca71c01e06c77591128b90bf7ce0fcf00046b0434e30d84d4fc3a4d7e2724f63ff3aa4f3ff6c15ba9e526c4bebf1d87100434cd395fbdd34a5e7097475949168a96bc8d308f8203799fffcbbdf4b87860063f6c5900ed25594141dd0f5237c452b19eda62e63190bc71759fbff11200600cc868993a46ff56c8d180beb7ae3226ee5ae2593e06dce5795802661c5a15700615023a2d00aac7e18d9d89db5a7a7b1a9c12e1db770bf8063e569e0be7b3300b740991afaaec45680ff89844a8b91c98d6539b25b7c150ae773dede1e05b90031e9a9d1331cbcdd63d300aa59ac64e90199e74bcf81c9de2f00a76349e8ac00fecfd5b4be12d56307831685104ce448a8bf9ab75e1cdb3d7098d00a816932000b1eeb3329099f14aad4b766177e87ad47991880153706552d1c8b01cc4d9100e37e0c88bffb75dee15053f9f1b58c8329c61dea938a220db170059dfee778006c70495abeea038511756c3d3032edfc9da35892fadbafb857d549908298db00a733c16957711c2e01b3be280210ff2784cff59e20171347885ed0635dba230023f47651b1ffb4a3406376ef30514b0e4c603fb1388bee1d78870ea6e0e1840080a09899deb9a875cdd84c795a4667e15d4f8862c88f0b4e6788009d9b8f960000e5130758278f41ad68e32e17d6ce73938530d011850023dd82664f323c4400bb42ffb06e8791d0fc9975b154cf476621b327713c3605abf1f6de75c55e19006a32bc77ecf0a12a0daf843e5faa227b78887d46acf639866d8bbbfc409e5600ba8cce54e2a1cf510d53986d43d44091603d7c833337fafb2bed11f0beffa100368f527f1ab61825f69fe3d623c0043c1aea33eb8f3db5fcfa597eccd520af00a87a533cc4c3a2c2b28472a510e575a5521e13caee8ad05362f50aaefaee4a000d4e56d9b42d3f59834016f2b2aa312051f6d3be00f4dccd201776948a45510064948c19ff494fd4e1d34dd49c2a0550dbb194000bfa92c8666fd67c282814008deaba35807558c3d722e821cad8a1486739a1b78134dfaddcbcb29f0d005300ecd2683ba079586d698f24220285fa75b1d9c73413cc053493dd8a178a2ddb00eecfc96566332430b943ebc2f8a5ab388cc861f77d6ac2d5be46da6920d7d4008ce7275b4a6d53aef14c248b8487cf58916ad65d174533d7cdd2d1475c128a004e2e22e10d8976463c3628f0b5e4fcbab781135cf2a313d4a2b46b89d2dbb2004423deb3e1e852b8e58c1f58f3d4968cc886ea07d7f8953932d7e20c69215000f54e0dccd25e73d97fe5346f458da7b54fbe05fa3211b4f7cddf8b2564745d00e77f52e47c33d453ea7e69fadc56345d709b6c738a18798b9f38a95717372100126c74005153f8bc2d0f3fe3a2b7299d7319fb9023d409cb3a55714c1b7f4d00bcec5151cfe651649df78def9a98689ee746534f282ea7ec5426ddde3a520f00167cbb6bc5b18508a0c444a22d460ce681112d16e8dbcc52625a206feae39d002827a63b4b18bd6c7f493c612c025af36f7d87cfd83fa81e7e578fc238dbdc00cd216103e7b914b8516725c151435ccab6303a29007f05d32a1ca70d24f38f00eef6ccb1ad3bd85b24d427bc5c42f5bde22f4220669fc6f7ce8bd4f3fbb9dd0021814487ff9336aad90355bc56bd378054d4cb3c81b5c2577b512fea6bad2f002c71dee18aa0b4889bca97780aa52e6476e9f48f50e5993cf17f87d5e33ab500c99bfa563a2e777f8df399111cf1dbe36c53d1edbf8faa1346bae78858ea5f002e09426f7bb71f56c4876c9cab1f5bbea7d1ef4a633130efc98ce20763a46700bbc2aca4e87d5764bdb94e6deecd6b7d83310730b003758fe6a7465e2cd9d90018766ec1f7039f437d4c5b36fc8133f21147c2286c2b1ac9a9b8a5b62a4a7a00bc5c2f5e1231fa46775e0a6cdb779672cb37fdbfc791af0ec99a5ac9b1799800e8fdac8557f9e8741036fa2f81e3e538c4132135e51a67f8f3edce6c64de52006d61ba08ed8601159b9ee6020856b8c26a7d17fff55c4d4e22e5b21ae8a87e0045ece26099c8c0de44f9417f0b5d2ef7d5d685af957251d237263a4bd1e3fb001d29c455a2d4fcedb7378be68ef08b4609230361b402176f92689b4720892300dfc9d0f4205c0c4560aa031a4a59d7e7d13f76d199555dcee14af64efd8bd6006379fc5ccfeb0506ea687627c9a9e20577fd6836fb70014f1e165982823cd600f198df5cd9d52c21fa8a8f10b2a53f545d70afb1ae4c2de2baf9ea6b02443600b4f64da9e5343e8d53bf0a358d753159be02eb0579084f74d09c203868c297003a434c76394ea317ac8ab7427fb91aa41669b4dfcabac29cb988844bafbda400be8599ebd7346974ef85ec7b61b022e8e2fc7b5124cea5c978b8db48b840480054e90b85373d89106516dc4be5f9825bf641c6e5d020496312cb358d807bb90007115c806c34ec8abb4efdbcd2c42849642ff4ba695940ea12e4dac9bbca4300f40328b566dc819747763c21ca3802ed822a0bf4b165a7f0a5808367f0297600ef1776182034030f923b9a6e9b15f27ee2c568aa90f131745ec9bbbab09e9100dc36b3bf7f38a7626ff26548d1a7bc1d326c71d97182c31f600f729276f8b7004e2abcc4e4363a69d9ff8867a8d04a3c94efc7c40aa7dfac4188b866e57d1a005759697fcb6bb9a2c97a6a0965bd4122c4bc086a450dc137e42b5c40cbc6f40019b2e040db33380791f5036161c7a0d7676d7a123a4ec6bb840432d196fb8f00f1323bace723e19477d36162ca5acdea72d59fd573759019a3433ae03f650400cb6896e8630cb8c47bfb7eb59818c500d89ec0f3d2149cb20d7adbbc2391a800fd677a3fcfe40f2e664e49e34d2c978be318dc9c5f4cc52677591d612c8b63004eec83f68dfcd09dcedf2d3b5d55a5c472965ba801103a696c34a0039b7f620075f53a544f77e33cb5aee7b26a36a39a8bb340222729657e97fb1418019bf90071379fd946b79d90b5e79e96782fea582bbea1c8a49368de677769c1a01fe5009419f8a1a0c5e53d45d3c5338a5197d4ac731539e9dea6e4a5a5c6888be16600b6c864b77c871f5f36cf5a201ada815b4806ea706a7c7d2b8fac8b6eac4d5f00c08a7e49340b6e3d99800e4b9f96bdf4a11503ed868604172447ecbb01fc8300562b120cd21f029dde99fc0a4096e3d70018832d2ceb8536a531cda9c88b7d00033adb7cd0ec0e19b9d2904abbe042662e3281f24ec45971238d9771d0856200dd2cb96cbcc6d18eb777e5d9a999b35e540148ca22a150167941cb192e5e72002908137dff8bcdcf995980d6e3bab2f5e5560075d9d0881e733473372ff67b00559fd2f116362b4a33783fc536cbc202b0bef062e6e92672c6e568644f3ebb0060188ff4b83592d07761ef285f0ffe82d0c9f373d0e3cbac542dd7f81714050071646b71b35eb4f3d0b61fae30aa14c6cc4fddc85006e588d7d16333d3aa88001c8771f58b812141734e85ef22460d6433ef89a076bc113c00c8e1b286f714000dae6ca085407e6d1a9af3b8649840b862e2f81997f699c7f46d8eb2881a8300858830f16b02d2975210383c257678bd1cee234be1228ddafe96d9ddce1eb100e36d4494e1a2b8f7867164f46b2506e10ad912cd9c6f691bb6cc587b8eb6f7009321bba0e1b8369a2c69e962fe54481f29a8e5dc1976853f95aa408d3eda68004fe48de08fe003228fcc8b8584f507bb6e9cd8833c6af8cd2d909e4cb7af69008f1dc87b436266f8455462a06d211b6b6ab0d222369522254fcf3bef3adbe100a8d4ed31b956c15957b5cd3fd2fcba052eb616dba0e65b1d1752f8ec24f7a700d5991676c7849c1676f6d395833823258dc308291583025adf2c02d901ee820052069134d4dbc5cf279e2092c9680fa11317d8847df95cd9bbdc4e92684dcd0057886c8b838eaa8755200ccf618d7c162e3ba8ee85e571440455f655ac62060094153108b93c6de473cd4c32b44d06c7ab91b6cf03a0678356d0c9a718910f00431692e27d1acbf24fb31237a8e12dc800a415d50ff22013701911d912661b00dfacf122985ee39b1b780162d31d902e9ee29bf9adc994d114ebb83149a704000a6299018df64d8e37771dd7a0153a1d5a8b3b197f7fd28b5453f140c0d70a005ac216b4faebd3c0a77aed6a0743db02c642a7e8864c5736cbc727404bf51f004fbd734afd6b4e73040e7a55378a8081c9efb2383983a937228efceb149da9002ac48f444550c9b91f5960662df8849f0652626fee7388fa47e2cb72502c4a0030e37fbef5cf219e20f00caeba68de8f78e9395c1f2db0c650e1c3d971b13e0086c935c1a442ac4160dd3c39cd4020a79d2264834847bad3431dfb24ad0fbe00acce7e058d76bf1062bc7f5a2d968b46b5f2323a22dd07d4e061a95c8e1ac900f8d13480099f27daf38d50ebd294129ee49fdae8510eedcea80997f7677ae400cd2e7504a15a9a5c1689cf32c5637cb40eb1197c2333753e8347fd54c228830035a226a780cc119bacaa6f45b7866c4b2d14c438dd0eab13e59a5ffbf4284c00f656d1f6956968b084eacf0b2d79bb8cfd04739228b6828c5d686192d297310094ae52d805d69677e83206438c423006ec64e695834e69aeea0a60d3eaf3c20084c995514180157daf8ae5d45a6959d164fa2f8f8b53bdc1149068a3ce05dd0038a8066e7e923f35eea71d2b7b7d14c881db5598776873c29b2afa421aaeec0025278c1879e0b488b75abe36fb2e25dbe7cabaf1ac93d0e91eea9736baaf25004fb8158cbe5693ffe297877b9460ee618e2fd0a2535ce1558e4669860e7d55008ace9da1549e4f69dfb4dbe37a36f37f541906c911f145b524a883b25b408e002540ffe67f8bf77a5205f22330cde4308ace93a6778eb8d31a89e8d5b6d09300bb42cfbc828f89d951d25b21ef3aa0bb5c05ced89cc475e9c5478ba7dfb45d00a11d26b8349977d49727b92c25fe0fc1544069612bab63b38fb50c65ddd2c200f014e43fa1c39c9642cfc9183b758edbb49fce565a88c0400c2c78c804cfa4005dde47e34fd710414be60d392257f86c4b1fb5eea17a9027dc125a9dcfb14500e89f0de397a67253fcd50c2b6bdc90eff0ef9896221acf4f3a9d47906012df002783108be35105461d7f18e89c15a02e591ecd4a0ca8fc8d7622951f3584e5001bd9068889cbece5c404c503c80a0412efee1b777cee68f94bede96150e2c4008b1f9cc77c1b729972ea4c2be5498fa9fe981f76dfe584a4cce408817a8ea6004d1f851183d0ab82e3b6b26b53e7468741882881aa7b8100a26adc99c24ea100e0cdcadb45a97901333019195d0abe7b1a4a07bfbc4fddafe260e1391be46d0005e7b7e69cd52fcbd0a9ef04e324b0bdb7a71ba76bacb9ec84289dacb3e4fc00c90047b3f00ee2869e189c0232be855a09b924f9928ab4a095ec83a8828c2b00dcb26e115385f29e8e9554ee274ead4dbc29b903a39f64911c09cb2b2a4b1d006ac0df159d6735b5b63f7674b8f427d04657397dac6cd0c4dc80b3d879322400198a398204ce58a37c33aeff811f108031773426b23865e13a6e548eee5db300f6e9c8d6c8ace131fc043d3171c215bfc076b61f9ed9ecfa7df9057761575a006d6224cf457a424b10bff4d8933f9f836c8dca4f17224f7accfe17222737770056ee3564186d491decc10127780cb5d27c9b2a8bd7d1aec39754fe0a26d64600b399260de0a3de3342104e1fda6af33438d8580ed1a6c38c678aaa8aeac05900b63c3c5c5cf5a0426f52bbc33f62dd58bb678f68074f3f647e3cee83eb54e900891f86619786a11a54f8204d4011434334928a2535167f79ccc43c6a02dcba000026e3605a4d07ad751fcee3ab36977977997a9abf83af819b2574afab096500425d3fd806575e929a043b11c16f14db135b9f5f61ed117d91dcd47c08dbf3002845879117c020cca7c0837422c77c22357755f378e3a42fcfef494c90389600eeae1cb6278265bec8f04d1268d28ec539fea0b1efc841657023711fc1dc5c001d4f3e43705236dea41e91e5475977e7168faa185053ee7b1cdfba043e62c000e4c9de69b557c17a07edde6f0f085177b8c414bfe053d03d49194910159bc2008b2306cf202c50354440c1081aa63ed7ae73d55fca5b3a506a3e43bcba885f00e38e3d279ab4f1b8a9fc8276ddee435ba85e24f1f8298d8ef3e21e4b12851800ce3630a0ed27511881f5c900cdc97f10f510bc6ccba20832550db187724c170050c9e27bfdc5a4d43b9613b36d15fa8da98334541dbc7de09b90e484c291ad0095e3ed00d73961700897ea9cb5288f9d833172fcb067948535774f47e1798100d55bed9527725199f0eb9f4e8f7aec38093400df735a6e5d127e183c569ac900de74e10f3776540ab47cf3a587cc636c1c1d994763bc1f508e09c1ad60e7860018bbf2591a4db0e9894429168fe5c5ab182da58a18fb457cb842312b74a088003b475a492439900a9efe889119b98b776f29320ecff27351da27871f15d75d00074a965f5af1c1f20ee161a9b95c370d02c91811db3afe3e566f0dc9c7f15a009477f2357ae8c3d9de7bf323fde222a629c1e5e5e1b0a3805d699a7b99526d001ee46efa06bbf6ee741dae30691fb0690d62cc65b45cc657df7752a6c9b1170052e2830604a2a436a255585c345a1b8f69e58622b20f2114f09ea85b24f07900226ea1bab77737e2f579b8c173661ec7212c7534943741657342ef51107e4e000c35fa9582b4c083b8b0d3dd31f00272d3ee43cf87e70b949bac6ffc5eaa1200ce4584fbc779943018b7b21215f7f0e21f64a511aaca445dbe0dc9e00ffe87008da1a67447bfe3739575b2783990fb7fc876c45133dd3b87284a51a815f3de00549e49810f5a3cc089fecd0313fa50206be90d597dcf6a552c2e5ba21b0a0a00e031235af9edff292b68d15e2d03273f740a8ce91a0a81e5268a3a4bb7203900428fa136baa74e9dbf9d9d2b50c77594d257e075312c24b5c97e84671b5fd100e0f826a0dd3a4d8534f0e43db40914b9477574498979a7f6210e4f4cc3933700d3cd089fab37f1229321c0ccf25ff48194a631280377e7b22aefd973534c4100a282f533bf013fdacde51c89fd031a3a1fd18d6dd1dfafe76eafa68939ba5d00a884eaa02747fa434dfcfc8236c803aaf636bd0a67945e4166f8f30c771f8000ba287617c2c37429f3ab774bc15018a27b4a03c786dfffd1c496baf59fceec00553b20cb20d7cf79ad27fd7ac079e3089fc1810e150f89d5892ef1720ad96b0039e3f4df715344437ef68e67b3e3f5e48b41f2c6ed0c221da5b5d94224856400d7873c5213332339eb9a16f56cdca3e383865a6cbe3c23f8db7aa4c175993f00c0333ed6df3bd29b9f06acb99ed14d383c9fdec36f552de5569fd5a45b88da00312cac8bf7725372dff232e5e0bdde14c832c8635107010132074c8bdbfe9d009981aa13e9ec0c1fbfb305b59f7c7228e85889542276315771f983eaf19f12004d728e799efe8ce142288b107fabb8884e48730e589eeb554584ea4f5db9f100dc7663cbbaa1ffadccf3c8d61c152920a1bdb44983d445e0d8306a487162c1004f13a8cb689be4ad1dfa86291ec9fa2a79750a0d639793c70e5e3d92fc80b400814442a99265020059ccdcb0eedbfcff4564cf583cbe77f2b7a5f0296ca6700002252265b875591025b8168097147b503e6cf5e792f579ef5140e15c1acacd00d8e1550ed1c361f726e4f0b098fc98e88f6322f7e0f5d19c755d64847ca280005a18fb81ae368d65e59180c50c2720cad74b857370d9078663156daee8f69900901045a99c5c2ce016c29e64c3572bd00bd1501d55a85a0b6ec06401f5953d003ad6b28024103e3b0e60a95f1116b6890ab7548ab064fd682ee55aabcc460100ca8d2f2323937ea1563c0967b1d9a84489ae6cbf97c11e2e285d8b3549afaa0069b1af37d9af90554a650774fec84cc6adb178eb69b44a514e938b841b0d6300d3d9a75b6de4ccbccdb2735588edcf5fff03e187fd16cb30637f45ac38690400c06204a30bd5dd81ce1ba60e7cfe5d397b76e609ead0d3b08c2eba319ecccb000f77d690f7c1915308591bcc50102742e1380d6dee9dc4a137815b9ea89cf00071e07e58c8e5aa7d5a9386c717e902716a7790082e5bb2af315a0b2afbced5000121927156c85ee1411953fc70156c3941f121a4abb89c21294e7b19174dc3009659380336613766c130d118116616722c8a5734b3d9892f57cec576195d21005bb93aaf65ae7891f12a7ec0ddffda7f0d33c205c901b0dd2ead97cb5c080900e1485b29b4f7c77a3dd87da7f1d2bc218acc5a6991d746d92dba54d6a8802d00ea484d559adda56ce746b1ff7dad34816d3cdc80bb501f9ed3dc73eb7a896d001852840d7e0f9e367a03ed7df9961592ea86ad2ca1bfa93f38115121f61d090056c9727830d1f6fd3b67eed63b6d20435d17068df9b12817c914c922d4445e00a84e14fa07d2782593f5aa51ad3ca2ba2a321d2f2f242dc4bb73e905a3615100d949681fdc3891bafaca80b39f99592d7276bcdd84a613ad1dcb34a99482ab008543351780e4e1299b7bef6c211919223b49ded65f824b1efa6728870d358e008cb90a59031ebf107873e5d20c43259f66ad922c1cee2d05804d9134890b8c00bc0738260dcd15798b1d5f79f5164c785efff6debb0fc660130d10d381426200f6a6f1059c31519fdf27addd971c50478648e3e00fe6be7885c657ebb1cf57009fff6bc96ac9691e792602dc322b440bdf7e9fbb1b7b3a1ee2b1e3ae5b5f9b0004c6d21e6bbf4893f40f00cf6058291139dabf32fedbedfb36bc44abbfcbd70037946160b8eb62e53dce5d4beaa4745875731ff11ef9b725e59fe546b7a2b30057ee6ebc8ead7b87b217a673f128abb12f01a8ea9a05296c408eaa020004250075b8d4d6e69bbe211eefe570859a3015916a4c2520409a241705fa4b5651fe0055674142f41b79ec8eceb3b46e4833032c078f7621c03b46235920e27ade8400de64846d0548a9df5d998ca88ccaaf252e9e42a840798220cb814c0a0db56d0071a616d0fc2b01ede9b1f35dfe90863a2e92f13bbd534e19ba301b56c1256a005d8a6ff83e19cdb871b0f8ee93284892988b50eb0361a8038c39dbd43c347900f340a4fe5785a7bb473f2ef3a2372f0336abeca51a2b42b4fbe9e480a1fcd200c6c6152b203fd87700398ee5a370f3ec9b33a321d440be1c07facd921f24130096da2faedb232572b155c579ba00f8a4cb5e3eb468908ee50ea8c563e9436b003c1f8d0f8105032b9ee97c0249a7a6019831e3ec25e8bcbf8a66091f696c79008c07a797eff4c6f195ec9cfc35abf1fd83f1f3d21b84061f047e81c8b5614a002fe8c1fbe81164f316a5d1082cfe63abaca4c8312e2324df3dbc8a3075a82b0093ce75121ffb69ad3b2f2fe2f96b60ae34c5a8dca1679ae0a97ba71a5e875200b2cda21d36139c48a7545271d8e35e8383fb2044ffde4a31f9284ff05462d900ae1dde6268a2cdcb7392a69dd4f3f5bf54f596e6a416194365654e8952249c00fb059760095430e0f6947833a1c9a029e0fbb45b5a12aa6830beed67c59c120077eadaa87bcc2d48371e1debb84acb24ebaf60924672c06be19329523ad3dd001c5c1488df34576fd71a1ea14f523da591cce78bf99b68a3dc073153b51541005edce180d96c970f3fac19595525d8cb0e199eb7f18c3350a14646f65b2d6700126af603f20a52d09aaea26590313c1b198465fcdf1e35ac7a6d504223bb6500c3a2095a494f9b53ab9bb7049b70395f2cd55aa0c9d02002ccff7d2b962c0b00e7837ba0d504acf3d066404266d64dc25c0b74fc6c5cb1b1bb415cbf839eef00f447852f270d7ed38015bda97c4caa5af34f488a435caa450e69a4b51f68b200f0f3e4376f23414a4b3b204cdb4b10d9dfcc29a884c343bcffffa8949f885b0016250101395aa45fad155d51104e3a1a5b5d3d70665daff17729c7d62a4b790014e5130600c40e267643cfa6cd9bc800e245cb0a46210f70bedc20a6bf68fe00d9cc1ca76ab8f9bb79d1fcecc85480f28888548b84b5f86f0aed624b891edd005a35641a4b5c6a32d32f64cda3d0b58414e19ff3630f14f3b15d84d10feec8003fc8fd9c322b9837874c57c888487cebe1de3a28d1c84946c52efbf14c6c9b00348f4c4495c7ed45ee3b4a95eedda3b20acb9cd21b9bae700f4fc5ef00776800484a59493d5effc5c551beb0911df58e5ccfd269c7f7953c16606b9356897a00dc8083fd9a528d14c04bd70794d8f5c619705fe7891b06f61209451436a876001c2ece5be7dfe02fcab3988d5e444bac6d7c72a8bf00d68f9573fc381bf6a100e33cc3d7387be8b2f8387c2b3f6ac95e3d70d100f4e03247ad7e7b585262b0001e688e18e0bd51a7fe2f963298b9ee790481df2411d230dea6872dba152d0f000c0e7a095a887f6785da100b94ee5ef3cee3b7611c8f0845f314b33669edfa007d10a76a312a3919d3b56664c270c209f2483f7a060c5c33919a83658b72cc00df32d1d20d2d634eecb63c1c75959d41f015c118cb89f35d74f7a439986cd1007697b22233710d604434fbe305194d80c89692f85babd4456187501265baeb00f70e34f9ac7ed0960a0945743fa87d9f66648d8d4d58ba98f11325920286570003fc973ee5b15b62a3e4c3ad6790f93417fb909ccf836471c5ee37eae6524000080471db81bf76583f48e33c71908c34c72e38a102fa1894196224969c3ace00247968c0634f57eb8fb69ec5ac57d3dea2e969722894f42c51dea934f6c58300cfd2c8cb1ea706df0c2d2161d8344ca8d548a0332e6f16c3733c21c1a3f4a40009fc64992c94a91ecb75e4682cdef5dcee0192be45936375d6f3cf0f1c315100afddd8c17d26b31698bee1d143cd9f4435283881a8fa848f12c46f8c99adff0096aa8e080af42f98489318fe6e0d3c8cfd5157f087f1c4f8689a0543c3eefc008ccbad23c00f33a9d3fd42fd8ad3c0a4138cf98572b8d10c9922afbe74e5d000c4a845768bdf3f6479903f2c99e0b5a9cb253b1197969f7c9480ba3c3510f400452cee753f7c72571f0af35ea6d8f65bc3ab550ebf25b202b917c8226e7873003744e70783df66194b43a79dcc5b074030f555328bf14d739a553d6a8955100013e305be380c01ff7dcd890db38784700ce970f98b47bd45318676a50859240074cb6d97687cc7a35801bdc8ea9a274e67faf4026dc36efa1f43e87becff9e00a0f34d26de79ff550d5a0f3f043cb650bfcc3b859689433fd39e185ba526600049138bd3ac7461201f6d098a13716cfe7786e2343c9047ee16ef6287796c3f0021bcd0bfa4a513bf32cde7919cffc5a363983049fd55b0447cc533c1ba01ec00c7580256e97456a298207d4b85ae8c8a68c954a12514af215dc1bd066ac4ef0087fa79dbb00a1f5a9bbc3f4053bb29e068c80823c4ea6600ebe2a7767b8f1800084da308b3f724332c8db48b329d89c54503aafeffcfb02b8fea1c3760aa0a00a24e9b3cac2b6df80a0e30094d4512a3c9f106366a18270e0fa3c42c09867100edcd31df617c8aa9fe792d7ca283bd023a0a6d33cf1c71ec6133f2f2a1c12b00783626e95c05ca9777e58fa43404d0ce4a3290cff4fabc6c4bd3f1a22dae2e0038f4d067090ea12cf6c39cc0c3ba4940c4f3b87a7c45e703c86a0a70a35dc2006305bb25962ccebb12d363801fa15c640110aa5b0160a72e207ceacb591b2d00e62aad8ad4f50dbc4d071df32e80d94dd2b78f099934084480745474669f9b00f173d49d810a6f1927f57291127c0e9c456f97a0774477cf6312b07f46bd7900c9e967e40e1512ab0621eafc81a8629d038133107f4e756a697c80bfd37ef1007f2198f3bcbbdd4a2d22a1f07a9f6b9caac9c261b27f9d5629c91f8a3c89330093fcbefda743def10075640c8e866420f73f7b27bef7193c9eae047df5f120009098ad1e1bd4c9d43e1174ef0aa9cf91cdf95049e8851d0fe349b9f263694d0084f2bf35ffa68a1ebeec606e59c83811245893fdc4b0167a0663ae3bdb4bbc0047118e1e636eda3e9ca6e29459cef08ef9fa4030916275c0fedf1698c249b1005e4917eff2b8c17bad3750509b8fd96cbaf74784a29705458fc2e82b136a9e009ee45ca56cd455d7edccbb9dc0ca52ea991dce0e949fd0bde16ff6723ab5b400d681564c5176cbcf4cad338c25b22369ce3e5439d68746938c874d94429e8400335a5233be4cc58d698c0e1e31076890c41e9f9b7ac09a617b7f46851c92ab008f577c913cfc98ee68ce8505fcd523324fd79eff4ee46bc737c28b9b846ac3000110550e406d10f487f9755653494d3831c2f01e1857bf8f03b3b2ba6e3e1c00409f870c172e846b66488580436650b63793102f6035d6bd2d7871e3f48491000450ab1c16aed26e03188ffe7235e4feaa4e5893cb8aa53bf5af22c091290b00e97d49980857c8f8ecf3a85fb77ac201323a4ddbe7b781e0b8ef7cce31ce6a00bfce8e52b89aa43be77b2b5c5b1554fc037003cc2181bc69ec3cd677f8022300e77e7c6289e648120d36fa73c4c32643c2ce45e0f7f87d9ab941e31d9c09c300b2d9817adade793053bb5ef10a1c853550e240425d8156989fb6880ddafc240064456c12bfed37a73c7fd99f9d87d8769f258c5876ff4c6695329bd778a4020084132637a19ce95fe5615cade2efb70ff6d66bfa0ccc2a31f1c445dbbff97a007180b017ca41d6ba8c5e629dce33c40dab823884f6cb7b8d7d425a1882fed800ecbd29191619523ddcd98ac3810f2fbe921b11fde2d74f154884a5ba028dfe005a5bc815a121c80cb8404c6da0515e340e56d81ec282dbc847e3941ebf07db00315a7df680de0062a7d210acd5382d224fe02e63099859c32134cdbd89c4dc00252f0b769b27949bf436dff7d7ee8fcf848e2294dcd30d8b01acfffcd7d2e9004b6b8b18e49995173c7db827c67887d2630cbca42cfdfbb6234b14a0717e5200fab9ed1289af84bfbc49bd41e6019048b5598be42a68bafc6f50fbb0eccb2300516a0843a081fc1d053ecf08a2aba7090a447f62dbe4dc36372d550f6cf0390084d7f2ab7f53bd824ff1485cdfe4611f900473607067d1724de1cc2b2c990300c632d82ecf959192d86b3be3ad1efe84c52afb4806e20f0e96b8e6ee00666f0036335db00c5e9b252dc673b65c97d5a18c7221d39de87116a0b9977f8b154d00ba4228d2a8ec9e9250b3feb6b7dec0b8563727d74369bf71166e518bf0b44200f40189dd655456005f4f8fbdef7041dfb95f24e63a96d128702cf9d06c5de6009e875dc0e14c618776adf98e0b46914886d0e7d57a7cf1fc57f753b32390eb00dc67574fd0c76f8b6ab835a0d3220f3822887a2d75f894a447d6eda9dec333006de68695aea6efb6985b87defab7249708d28464ab3f256531477c5af2cb6900867b05a745e094e548fb11861e128126175033798ff97fcfd85ce549adf81a00c9798f1c0bb3de295effacb34188f740232794ef4e6683e443290b719bb91c004ee8f30205738087b26eeead05d41638bd06c8e32fe0a26f98da607a908cc6006a5fc120177017f78c6d3c1dcf8f15f18d541a7bddb5765240f811d3e8a2e0005ced16d216e06cfa470b22190ed33d427d5a111e9522476ca1e9bf1b8bd35900df4ccde56b233b792fc7d06c024e9dec3655324fd3340e4d614d01c14bed120001356b68790597d23ceb9b518806989655f6de3c56f402ddc1e6d2c7fc01bb00b54be7093d957be98a0a2e7a50ddbac80c90e3a4c59bd26b7912c4681e65fe00620ab37de60684799581b14e1b7c4b21d43282e0cafdf2ccab926204652faf008acbbb56e331e27656cf684f1b8bafb68d172ab5352fd74580cda3ff2b083e003a3c273a67376fae053cab14d4f0ee76e051f2e07c487d5aa2d2ed74650ce7006c6b65c1a49200eaadf2de191c69037b9fe039fac3f63b2874bb5cb95d1f9800970dcd7641361bc5020833349735daa22ffed70e711513811b56b451c05a5b00bc797499587a1919ea5da143531dd6da4085ef10849e672d93c6938ff155b800177c713b53b1f4cea11d743acdc4c4bb7fbf7305e14347f6a74194a61ab7c10071bda21958564f4915c9964aa5ed4dcb5fecbfeaf3f295388455de00a1cce0005b8fe6bb4a5c584a84ea95ee3bdbf919f3a42207e035ab8a361e6e53c1a4650040d16cbc60a87ff4b3011a229f068d7aab3624c8fa348dedca23be492eb88e0005d3ab34c3a32c4cef412877b5ab2d9d42477dc8ce95a11540e3cf8905d42a004226286fd9f79aa6eca3442ebc5e7db7c4e50fcb0866a0c2bbac90808a26d100e364da274b0a379f117f799dca4c98f5abb3c757799dfc4ebbecd31f8924860042fe7d4a1cc4e2d3af2a20ab75e327b9de6c7f874fb9c458e2abd16b353a3500a5fee8389c5cf652b35b7f893e188b908fd2001ffc273a3754955b76d6d17000d71c4b286eff31128bb14bb42d3e843dc484950d25924c2f7e02a9384df46600814f896636bb4e6a36cf8f89f4612e5532297a08edea11e7ec429ccb31f297009f1e4906567108f4d5b29f32d6adb00c93216e7dd15a5145590195e3825f01000b0d13cdb9b7e15434c3556e8f6b66d760cb922d98a6bb4b745529fd0923da008adcedabe4abd30ca40ca5799d5f1accb99932237b8dd726339a1ff9b67224004d5a060d9a984c0e38182ac66725bb4c032f62a4257da4c249f7b5a63c4cee007ff8b7078c27f9dbfdaf72a7e7303904cf918f1add80e44b0b3f3c6302b95a006bc793ee99516bec68816f6b8148a250bd91ba15ace66c1ae0b5f2a86aac9d003b6894d9a43f83141fad6a4455aa8240afa83d20a5cafa12db7a8adba40d5200910ed68aa87b6b525dab8a12e8544b0b79a92e1fa03da6c4401ee2835b531700967e59a694d62c6cf4d9639e3325cecb8a7c23127f5c9a9bfb9ec99806fa90005733a58604eec934d78ec4d5f5b3fa1c5243f55c4c5431cbf7c819c2c8158a00ab9242fc43d534cf42d22c5b8482edab942c16fbf0457becba15ec4c9ecd8b00f849ee5eed64f7d35ec13a6e203bd428f1985b326bf3558fc5cafd66c433b3007dfeab587d55b8523568105d368aa2c635c2dae8b45809ea7c06aaa6f953fd005c26fe8d928191dff28dad3d24f8c6a74178d94260e8b22c3f60ead7ce46740019f8edeccb584c3df2d1f24898fc2f50b45b830b4792a51f906723f024b2890002cdf0328766f63c0b475e3259b948f1e8d2146d71562a94e2bc310f115ad7009b4edf2c7bac8a201f17a57d035eb91c1ad35c1e71802c923594806824c63800e36bc59c18ceba90e8cfe10a5590d895c4d444a26a4aa8ef4042a2e99e4c7c0040e67efb6d0fe472a1758d9851df167b4f7251a4840fbaf9cac2f408ce9ce2005402748ed6ce6cf8dc4ccdca375bff62fd7a064a87768fc1ac8d401243a6fd00883cccc2c4680120904d0429313c33e957975902d722715da82b3946ef68a30035a1fde364e33bbfd3eae2196e49e1e1c526f8ccf4b69c82cea3c9fb4718cf0098aebc0943bcca10ca4d437087e0ee6397897244aaa0b8f65557ca0e3065f800a70f9c860664eb9b174022111e8f616f3878d12cbd33fc8a95bf32cba61adc0022534cbe79ee787e4222fd9ee88bf8773759f2790adb1aa329c8d40a86486c00370b6b7639f62e0fa2442a0789bd7ab68d0fb8a513f7610c9b1f86aec2c69400bb9b6385795cb5c5ef0b6d3bb380dde151f145ac2b48407428f8ae22c42b990038e19b39b5cfab5ba18c46e2b6649076d201241f84fde908632f51e06fbf91008ded2c33304772f02eb3a17d96ecd6bc65eb345c8556fd836324f6cba2274200efd29a3eb4dc62584eb22c0fcd844f4356c1aaa195337b43d66ad9cb63417300991cca5bbb49e8629127c65934eacbeebacdd6366bc961f756739e4f244d250068ba3b515df2c6cd8a4569e8b88274c13299eab0473d50fbcc9ff8448e02f900eb7ef67fc6052642000da288fa0c32b5aead0902694285d2c6e0bd1db7c0c400bcf42aab66667dc217ab2316fb548f76082647257e3e4bf2a7a5efd95334500044b8cf02067517c08d27b988a4868167a18f877528b8e47096284a22fe916b00f4a34eaff4c56c5defb489d2b98af68f4a70c6444d799be60af1a5732bd218006731dda9a58ea143fbcbe039f86365daf306370d5f0940de86acbe37f9919800933dbf8e0188d11fb5327d07608ccfa9496a660f832ec3a771dc5ee2b9375e00e49c3aaf628eecdd85bab14be0d6b6281c1dfb8d5e06344ad01a5477ea1b5600d480d196781b488dba46d84b17cab118aa0d84c67f6235457d288a9b514d3800343df2d9b743fd04185f069300efd6d8893eb6587aca4af08d952a29ebea840054f634b8e480295b06aee4b55dabaa08cc25de53e1420456360aeb2f59c993004460c784ef22a1b6d68d6aac13ff169e80b6f261000d059db9eac80a5793ff004edc7f964ebcc411e5a69345d1e5b2fc9603cdb61f5c1e54b311a5dbc97f480095f2b9db41422fa42ac5b34160ca35f61445ee1b7026dbb75e933937e670e8003e798e184df2164eddddbc1b96b810cfe58757ea0ac53c3c038275f52261960028add582f27fbae169c9e97c7ee454356aafe21670c79b47652c69adb374bd00b9f2709b6597e0e7b9ddb89f2582e6ed2104d5f644d8eff95934abe28e6b3500cf94076ba1d6d842df855e71c7e592935e8d98174e95a9b8b330f04cf1b38d00cb3c3f933a76901586b6be9d0da962e3a0e8ef1f63c2a4e32e87712e925c2400ecff096aa5ae2c7856e3a97b74c688bd24730c8cdf9a1dbb5d286b99d29bd8009a8a09313658cd965e823fb986766e2322a9cd5038d45c802cda07088757b800de4d2b58d2d4f666b67ce5264a65ee7de77a07ad9be2a866a46c0ac775f0be00d466887f1e98d6877104afb9ff1fdf517ba6b149753fa30ceaaf85f61f83a9004c254c1a7da0e2a82c2cdb90587e95cdc3f05c9d1f0810de2719ec0564955a00349dd4946d204c4aa1e8d89a4378ae3882817697edf3bffd0b256b5b3dbb53004708971d3f04fdc85f9c620e804bec09edea7ca3439ffb16a09948a420bd5800b0b8d5d3adb91edd308928794c8deccf27f738b5883dfeff0591f0984c9f1f008c8bd8a10ceb3420adcf89496e6fee83c78c98f13d7731f4e413d2b96e8a0c00a32330d871aa72bbf906259ce82af22342b6f0c1679d0b987fd3a7edbc3260001964acf839edd9b8f1c298dfc21515b7023f3c9a1503c9400123d974a95f9600946fb127386693f210b9fcd4825bb6d22e15f07b8d0ab36dcaf51aa66e163b006d2c33c77d2a262edf33819b7b67197f3d0b13446d217cb7934e649934052c00a12fe5940c924353050045bad52151ce4d977a4f5cd592987df4aa39e6bdb300ba479f2119817345da5aadfd7253e2d062e127bcf3427609662d90c4ebf40a003a7af9739d194a0c2cd3188c1074b0d912cef14d03be03f842c2dc9d9499bd00f47b5e9783356e0666698cbd2b6202f06ae1f491caf3e20f97de7e85dfa70d0016b97a28abc3c7d2f2edf0740e9d53aa65a6fe32defa37eb7179e82fef41300047af1e6d57c00a39ccbc0ce30ae133b94172461e7158091ad13261074e93c30057360db1401f82b3ba58438bc7b007662994ef119555a1c1a35253047e545d0044b2720614f9584a3b325b724070b5df31e3b4aa714b837597ac0f39344003000403d4048d40d109ac7c50eb880151747c6d72cc8edc7537530470adc6077100f68c260a1abd15de19c3bfd9b609fbbac368ce7e5560af54d4a189797a44f800c339a184669197de603079e37bf8f38bd1b58a0be6b30cc132dbf153368034007b2be55ad56d28beebb3673c62d5db2e5cbb344357a6089af26fc7408407830037232590580117da4634cadf60a270701142762195755285150c4078717ad2001a0cc237b108d65a77a9f46c45ed779920503ed674fdf3b4560af7ee324ff4005cb8643f4d540673e9b7084492fcf6129436655eb95a6c285145e7f8e761b1008f1ebe15c23b6dda8cc5901dc371a406a6b6fe3a380b118e7b49349e97ba47002f4e8468ece9b6f957bbfa8f766f4d6968a19029ccd90b41e85125bfbb188b00cfcb71e04bf637631e3652b789ecb0016f53bd28bace21f4b5f1af840a048d00234c40dccbfedb33ab1ff829e9e6baa27ec22766f7a413b4d43493e9ba121300a5a8a501059a1f758b347c24259a2a87dd6e5cda916d3cf73f56b2e37bf245009a1dee1f2b0c75d7d4be09a74d8321314092e7ac345114b65425a16d7a958600d73bb48a895422d2a46f7367be261e95aaef79fd93656dbdaad753853f77660099654effc9a8a2cd4c446c29a1cb8711521f9ed35b288017c137df41efad0700274b306b00240e7aa8325f8c4056669ded620617b4a0e8f43b0d9591d2ca8800fd4c275a5e33ba9d43b13be2a658d329de2ab0797bda6f30e02551e06a2b2a003e05ac1faf05999568e424cd96be3b04ba0cd1b6d7181e6fee0869be7fb50f0025e8f340cb8a348f87c57bdbc6bc4f16a40493b16eafe658fec83b19945d1500706c98ce3678502275eeb03f530f3045895350add869c8b6b55b4f2cb8c28100fbbc3a404ca5c092e87e7f4af1cf2bfe2605be56188bb5852f67c72002c3010068e439edcee9ebe3c44adb33abd8e22bee17fc3d92cc53f145f9530898cf1b00b5d0dccec1d190154038a79f85fc5d1f481390a0842a4202ec3334761b88e60009019b6438988ac49df604d7c3d4e348a4b909459224ab2e2d48f5c519128c0033d3ba8ab633655a2b831126b15a9211f9f31c11d9ccd677de5c170ed82b3000e927413b7e713a7b06e1828dc289fe94a92e7eed47505cf38eb4461dd5924800e21a467685f9416044b22ee3202edcd22cabaf004a5a6a130a5434189c0ea500ac098a5ef07e49db9c32881b42298c0e80717b7adfc4bcdfe053bb0c03d9ef00d7a2157736fe4d7d30ad8c90941c720434e5f07e071541bcba5cb0a3b2a15b00cd43103d83301d53bbfff78315b767c906ed75a7b2834378d90279cfee389f00a571e306881a9b2060b518beb387f2846c5489cfd433f65e703da370899770009fda450afa04e6b6f3cf2236d4f93ef09600b0f865eca085058d219813635f00b05d7f18796163d29ff29baaa851aae790e6003438913777a1cad238a6cacb00faba470e1b979b615ccec70e36f9baf1f862d8e63c19e008a6db383f0e191a0058d1b950e20b4278c4e0ef002d1c8ce47131cd1fd2f62fe5e0cc40d39ae9180010689e1c0f7be5da98ac958069ea964fcfe4618b276bf6680eb2d67238526700818273b0d7201010c3032b115811380f258306e8caff67bd077ba71884cc4c008e51d8b6a541389166bdae962acfff3c844d6101c5e19c5dff13817ebea04200dd1555bfaae3dca06904ba0976eb6f5a63f3457d16282ab5050285dc67d73f0083a399b353a2f68f066377d8a8caee8cd6e00e969bb0c78c3dd41b2c377b2900e65e8df8da625835ab5fef1a23a40dc6cdbaf70ff6ffe482d35d7c6d3037b300d25dbac602dab9b916be10ee993f1b05a70781a39023e9b91809602eefeec1004cca3978f35b9d10abe1597dbb390c4fbdd9a7c95620a331ee29bf78f2465e0048e0e605ff8017c11eed66ce97e30d5a2c8646a3edf2812c65e1f5419da340007e507f81d6361a6d9f0e69fb3b6af11337cf29b6a65075c650facca337413800cb306112b876a6f95c57a711f306a5cde8194f254d9eb2887bbe81a1bc0be70095ffc10c210d0143b2c6e93333e0dac005986de4246efc8cea6394a59ab96800775d4dc0f5bd9c45026250bd5179de9dc168008968983be12ce365b68c9d6300bf2c3c31eb73c1147f2c66e1a4f41880d070f716d1a3594d68d7a05612676c00dfd713b124c7ac6645a497348f380d684587ee9921340902f91fbaf17ce2b6001592d65b890f403b4f944af6fe926cd503d20698056108215fe53f4746b30800a2fd7d1a1ce807648933a17c73854b67849f28be3682cefcbc1e8579f809b0002810e6c11739f91899706788ebe4b3a75d940a39b83ae84d9e68141006ee110005620b9cb7ba87e24c761a6a06565fd4fdbdfaa514094c03a83cf51e85f8e5008ace483b2ed6f8a3c93782b60df7538b407a3400eee6dbb50224b7d60a16b6006d3c50de8eab5ced0af1b77e3b2837df5511acb195984f0a313d682ba69591001a8b8a82829ca348aa1875d7c6d69e6af1c9b6017c34490a6446cf2dd615d5007261686a4a6b413a573e9c58273447ffcf51cc51c9a742c9bfa1e2159a36bf00618a6522d65bcd5e6deced4ec84930d8c7b45b2ca53d8d359d55578de1486000ccf9caf061d045fffdb4360eee0ac680bf41472b452a68cfada08776929daf0085f1af3ef1a1b68e76c12b0f1bdbcacde63ae1350739c7476488ce1c6a4b60006e193b301c3ef41006aafc984b259ae2e5752781e6d938b36726e6a17fc7d30028e3654e3b03f4e40314aa8c620430cfc64ad304339d41b6532f1465f6016f00417a9b9afe79f2c5a0d43aa7ecf02c951f4f0d056ae884c1faa712aa1899500041ef996e98c445c372d9d011aee70ad9199bb7535b96a4ee98c90d7a9b652b005dcd356cc2507a1394f7bc63780f114c124128cd7ff8da4f38a130878844cb001cbc542c51725cf75b5a870ac356801543d12e062c2ad31e8cec0ce3b0c7460023141cb000b1ccaf37d8c3f3c5aa4e806b3d31be5fdede985f098753a03fd000836e0399e6df4726a241325e0a822f10e1e64b13d6f9800183e4c528f98ff600ae07ad9dc820337da10d75a95f99c833fecad0d50d0d65ba3ca06724f138df00902c48645fd26d6fa796f1bcee4eb96c9e50f1eac6016195980eeef05ba29300f6fe605ffdbe5e08468406c4cb54209548b05084dbdc0e31b8a0510ea0407d007bbd4fcbbdc65e605a068008678016da56dd85f721812c9111137a1dd5a4d2002fb29cee323b6d501da19265851a100cbf6071955b68fef650144ae5e6ee1500dfe9915f16cd90cb9b37ebc586494ad354061401b2420eef74a109acf96d3e00f8ee76d133840f9844b3aa0bfbef539d8d5f745f78400c6948f03fe7728c5b005a7ff27dd69508428d7e39cce9345264d38c9dd34296789d0271b62d8ffbc60047b8590102c8fcc34ab1e42a6c94725bb89fddc3589961c9dc90a0c383fe51002109927037c1be19ebc30f2f5b34676cf6413782f045b08ee8b58b53ff2229002165d12316c03024e8f8cdb7530d4ca6909d07bc86f44699fe7083c0c1b52100d8f844db2070d43261e8716234fb22ebbbea517549cc8fe6aed7978c35ba0200a9d54e9cd6adf57624306e8d2203e386cd75d5b06d18f7b1ae28586e5eec2200e4fdba7f7f98cc0a4def6604f8dfc88d36b6aeda49a79c3807994c91a85ee500e8cdf24d18aeed454cd877ec3924518982a915534af07d531bb94a74fd30350065561be52cef7555d5c3432eecb1ef3ee80a1ddba7a70fee7e200a6004951600fc697792a1400de4dcc2834c9bd86bf44f074733892f8c539ed2b53bff687e00a2796ae8fce84fe9651cd996c3c2a118b170a70aabf24befb5724b0dd432c700badb2dd77f8db2e5fbedc9299d1e144d95992615c27b1c7bd7b0a18df7731e00eca00e5d780fae7f886bc33544dc2e799f9cec10a2d787d15afaae756ff57e006cf7d0a1b5071418f4418575eb711cd088576a8c2975a43b223af0bb4c150a00dab1955c697d7afffa67b163c5f1e98d804de6cc875bb4a65fd444e66ec29e001097eb7b0a8c977f8ee4e0d25f94705217cc8032abe14eedee0ceaa670371b00b65d0a42a11502a7912dc0c2820639356cf7db1b9ae0d4d8b65d8dd738d53a00472179a59612fe2ca665ad6428245a9fc06d3de9a7d3f94a1269db73acb7400044d041720a3d10952a6d6bc5d0f9e5a2f9123eafe04c38ba4db24d90aadee100e55012aaf9c60b6e019da5cc6f69f3c2b2a5d8fd6c0903fcfa3b68073c410c009f1628efdad0382a211ceb301c17d5757e512e073fbd85e8538dda04a7962600944b72920cb9848b1784fc9e815c78f95f515daf9d6d906cd353aff2138924002eb4a038354040ec06059bee79abe4b056fcb9f7e5128fbd81e806088e19830099b250562478363d5b45bec5f648a52a33a518b35f8075bfeda18e0bfa207300d8eb4b5cc24fa59ba60aa33b1ac1a27e2bf34230361901f714a2f58ea475a200ad93422e02c1b881c6ae1e40db5fd1b3c9efc00ac0f156610967e83d5806590092b2e72072533fcc2307d988085ca6da654c04ffc67dfae21a984c0b5a9e3e00f2bdcd45050a9c0983a78e8ee94eb9625df93b12d8416460ac00c0c0c0a0110003ef9d5e316eda01d5b6d0b951d3124384a56e4056bf7ad24d45978bb86dc200745541bec163f5d3806bf7b758d45bb3846854367514f817b54796747f2b1b00a6907bb5250d3bc72ac51bb61bf6f6bcce9623a2487b229df393db4af9185700724835094b79cc15b40ca170cc0d1064317472b22ccc161ff9eb7793d45ee400ff3a057ede4fb86e53ad891bbb6dfe3c1598dad1cffef4843dac37402bf4ac00a02d1953077429b18f2a66482527f32f2e566217c08d991ae8624b9530967400e7d9350f3268221659b3f4fe4fbfdc8abaff20c3fcabfa9c8f5d9d004d55ed00dd68b9ad051aaf51322633df92610638c5de49b85cef9d2794d6545bc5ca5e000652a7e1caf518ae7988f0ea520364c2639857f91b92e4e3ba410935625ab200a260cfe2a8aab46b0c0a0a3d3ac232e4db625ebd51e375facbe7528a0222ef0052e9e94ca176d50b7b39d97624f86b93b1f551ddd4716e35033e7dddf33812009c097328e8da7794c4f98222bda0e3eb595d0f83ab97dc84eeba950f6c14ee00e6409e797c6f20880db8fce5f1c1840a318b537132831d185f7a706d799fcf0026266cf744990a3b831ffeba6ff6063a6442a7b7de104ebc43e4b4004c5fc700ac8b89401ded475a1b376df494b8e53171ae6e7c58df93e995ae608871b22000a1d74c12c417c08721cc65b2fda424b13faafdd5c482a6597b1fa5712ed9b80022e7a6a9bd291867bafa4353e737429620e38472c297ba791a079dddbd2d4b009eb6ae11203f2be8930abfa2af17f4c9bb1e330751f4db1a3cfe590e6c72d500e8b654a2ee865591c9684e298667606cf6b999958d291c166300c32900e4ce00d0459343d96bf44e9ecb5c2ff2fa6843f13d32d7a4189a36858e68a6f4741a0046272452124958d6cfae13248232faa3f96a9f1e56abfcc07b34a1d50300e600e985613fd7750ac33b3605a1bab4ef99f2943ad07b0bde7228b288b9d06b5400d5d1f53e19792271173fa173dc029f6ec998d0580903a97572ba35d43218d70095efe594184108088e32bf8e81caf5c6c9e4c5d8b9611ac6caaba135e202e8003b01fa8e433f598dfe432ea62f0d8d8c9e68fc0752ccd51f99b50b9869788000525b09dcc52b7c6c9e75dd73403fd9b59f61e04b0e2c4cb898070d035dc887002b96f5e49f1d27cbe43cec55b383af7a7eb2873d19b5da660a92ae4bf9752e00bd66d43d1cb49d3b89e9cc75eb960ff7da20f66cbec2be268fac1d5d1c17d100f52f6a1149c119377191ec72da12c59be8b92d847e78ffa43fb59a80793358000f0b3519cf5bbcdcca2cf4b63d6ae24f8773bc3b4f1d50bd93723a19e2281e0085517b86305232f41a72202cf48360659821b35c1f791b62e2d951ad0ea17900c09d6e4426cd6c9053a0e03c7c0207d82a1316d8559333caad0da02e72b5510090deeb9250d68681d34e533a35f8fc64f0364bcdfff6852483b762d4b4b114009ce276cb279cb8bc3bbb333e8b842fa2789cd3eb18a6f188d8bfbdb041cf50006b8fa3418440c70a5610dbe83c6e5bdca02baeec69af4653454e119bf3381b00b60fd32bd5289823d7f1b159898aa6b4bded3b4cbdc2ac768db042d52d0d960003e65188eed31bc4f958b1e8ce40fba5c3f67e4ede309f0f816ce016bf29df0071b6e2d2924507735b82c962f02ef716d08db15af8b6a8edadbdaae867024a0026274edd8ac3e9b12fe273201f4a1a93ab3fe056df6022d2af3563e3209f3400b26b41bb2fdb15d8f13193c042ac6cfc627695b0b5c1a681c23c79ff20936300e3b4be62e2bec0d3e4be865c0f24a3a1bb512f76020b3ab4cf638ac510781600bc3647ead08fc37523daa74a4ecc1e0a84e2f86868abd0c6bc4062fe99b4790030d5db5f96a57571fc0019126608b91a5992a51676d22f3b544921a5b0a56f00d39dd6049c39230d32c1d52db662733140cc54b3b0a198b47a787c4776545900061baadb65bcb4fb51e9352af4729bda4529136ddc4569486fa947b32a1db500961cf6c5c24d9cec72459a2e6a62cbb8027f0dfafb5c57820e144e47db9adb0089d800558406c230475e7523d0c1d965f3d6bf83360416d2c3e2f024bec5be00c0c9a753d6d8f7b8b085da3011ef5b893387b7cfaa9bc3819eeb6a5112158a0043d5334bbbd4a88a5b5d37d5e0466ec5469f58fa23ea9816bf8891f408469d00c136c72242c494faa3f509adb2c7e9718e4c0c0022f8e75afba24447f22a3500f8992efb5ae0b2e6beab663534ecb37b91d8190765aac1f8559e804995f4360012104b4cdb199b62d4fee078ac7f63eae8e0faa665e1a07ff9f3a338fde69900aa3efe100bc1a6dac3fa6c05878382a27383f126d32818d77bfcbf9e4b7448007a18da17f056e9f09f7b1acef1e78062cb6bc483ce53c7153ed9a99c137198007d406f4a20f6ae041a64ede5acd07c7845619a596aa62e61180a120c7fc4570000dab0bf5c9642b79d776ddca83e52f2ed436aaad4aaa9a90526e55e6b6147009b7b720184cc5635b7ecdb2a793aa37eb54c6e7b8d9f43a37e3796a07fcde10066c991394818aff9441b726601ce8b2d854402e0cee76f51edb03787a781e9007e10caa0d96aa414f1a70118980d8774631c10b77d208077d493a64ed71e020065ae1ea7ed0f6ee1ca2b5525e1a3af42a5bb5ad4eee659c61e7f0c24c8684100385692579385976213352189c57528ac6f068005ea7eff15c888a69e279df00069d860b6207d66d2a4608934bd9d99e9248736ec9c294ae29e95192c73a0be000d3794cf7a286001b3da2fb34775f2aa21f9a5abfacd5c4068086af8fb8a6d00ca7b234f6676eba22a90303a8dcfa84cd2b1c55844e3bf49a034b7ad228d0d00cc312907a868883e3cffa87ec278a75c3b89cd15924b5780560bf3b48af4cd005060bba413171bceaf6881333f2495023a000db49dbcb73177b4415bdd32da00c3a575ddd73745a8b873cc59cdf322284c85c7f82f5d5af86b13e9b85d519b00e9929db9322200dc8be76afef0a7136334dd67b838f782764b943d9407bd1b006fe8faddba8de94a050c1a48dd066a71d25c1375bb58c388ff6923a15fb5d300e64861f02aae64508958cc9618b90c4d20bbc63425dd3c5dde2ff4576a4f7500a60b3e81b4e5349a3ba6f6384efc6d050fb7949c33e0813d8723b4cd905376003ce43ed3684fff19d11e370ee015b63ebdf853aa63959cd3e4112282b0cba600c355207b05ad8b62c2bbd8ae7de654c8ded1f7c6793195b19bacadc75e919b009cdbae2271320726c51e26e7d8af27f9be590bdeb4ebc80bcd2f3ba114072c00ef01032ef34af40ad1dfb5ac819dcb8b3cede29040fd3327b20c4dd46be4c600413bc490e6febe3f90013409b239932c77011e7573bddbd98aeaee3f9f761b006f04e85c8ff5fd2c1dd54e9562d2866cf27cd96157a5df8ccd932e7a7be79f00576b52fcd5bc04dcc9e38a9fd319bcca8f9c32330e319e26dcdc14a970103f003c87c80544aa4e30f0f56f86920ab2c7c5ef25f2d86d81bd82e9f7c1f203340028e0c3dbdb0bd6a8d2efbb2f780dfdf7c8b0504aebaf76f1839d2ca29f8b8700f221213cf5762b77d9c3d339410769783d234f548f16fabb34f37872e043d1000a126cfe4819536e2dae816941a77efbb87f08f01b3e01420b7ef5e8382e6e0023a82853c4a667b128d275955a9a5233ebbaadd39bab742a293c079a16ac990043292e913e8c58e769b4c9824ded7d6906204ef01fe1485a40da55c79c428d002518d37dd877186e978c220a9e810a27e14142a6e8e446e0e9f8892e13442e003824824339771440df455bbff4836e8fccb30a45b7715d42d9e3e75b5bfbe300112aff1a72c6c7b3ff9e80df018dba9f745b249207c7e03b4541e56ac794db0088eb305da7958e93220d9f04004b851c2b509de9ff8ec52046a8642642b5b5007d50e5c16c23eb96356ee169ab28f1ac51289d9d8175610866a9a7873d245e00296d98dbc6117537b5657bb29241ef591c5d7c470c6a83328505355c7e9c50003a1190ea21956c3b99b1a1731d351dc0f15800d44eaeedef677294e6a0805c009d7e212a30bc3891beb15f6d33fedf34835c362a0d1f0d3d438d52f43a9197000d785726159ed32d2fbff40d0368252930d9b56ac2b6dcef333de39f890da4001a06b84c7fe6eadce9a3d6f61f5f0fc8231d313a0f0e64e833da3972f1e1b5002cf1819ea7a5e0f7fc486b529d89b9ad9e6fb80e1eb00a699995982962a22e001eb8bc24c86e3a5275a659ee5a7d4e0b3ae590a517e603fa89c18211a1d8da00f23b5290f0bf5b46047bba17f8a2ac2db1a31de1384dd91b009f0d8baa2d310036ba25e6ba04132ded5cf32a651e5945db0a6b34fe19c383a64ce78492baac00becf3118df309e0f99e4480443335d1c1ed5bef576fd1f16fb64b5c78e678000c4c4afa359f807acc34193e4cbd7777f0aacc0965aad67ab712a133e8e38e70025cf0753abc13094af017da915e27826d1c99a76c0858332810b6a01a4f93e0094ad4a7b15342c45d684b6bc1251c6ed6ce8e50bef3f57828d059f7637440c00fa1eee68a4b3453555954e6c96a9f6fc5bb1fa915e654dfdc9e120d8a960720071795eebc73ab34cddd3a3bc3064eabb4263e4529375fee62351466e6eac1e003e454273b22d827ff671f8f1ec21cfef3b0e11368bcf2250ccdaf80df9b26b00da4f9fe45f25e311ffeac5a05a04cbabb76cc0acd56d37aef95c426774c5bd00d0fc2a89f9bb099d6f3fbd8e2d0f6746044141ddac4cfce07853b1d0caf5e1000a24ccc9da47d5256ab4a69c364c0c62ca9914458df4a2f0fab2f150a95ce50008b0a7cc0d4182248caabeb554afcd9237ab065d0d10e92999aaec0277bb1200fb955624ff6c6c2097c7d40e5012b4b21520fbdbd833b4bd9e3e1023fa473500729e5b1f0820278d6da27e3bee52d7ec2bbcdc07e4400cfe8e13abfe4d164d005b40c49ae6b908550b485de397a01904413e8328fb7d54c1a69c1cafc73eb7001497ee9964546aca48b717a4e80a341679b9d63379c60302c4cecc10d3467100776a1f057fb6207f75f4e915183812529a23be8a871340fe1c204c2b2086ff002a1e1a739a0f392bfc2cc544966ef0223c68d120d6bda162bddb8e8dc5aa0f00ca33f242e47f51594d30f25d185cce3192813929ec3a9eda9842b1e488e35f00cfcf2030bf4817fed2d9dfa8e650b73f5ed46886175548496e3d21c43d266d00d8d5d02fa4d6289ddb1363df47d72e55c387869482794424ab718d335fd3d900ec9e3bb43e50f33014118f0ccd7ec246bf0ec27bef5eb9345cb50c92fb256b001d2b2530bcffb63a1294aafab05964ec6e065f961c486fff6b7d4d3e4f539c006e1f05f4e6713367d78c894a9c6cd767530d3800370aee989bab42fddb4f300099f8dbac41a05d1142d38dcb439be8a94cfd2f5a89c3fafe0e5da859d46f78005a59202c0e0d40fa15e1c36248f23b953e19ba53fdab5ca0c6a41161ed9cc6005023a9aba4c87b646541912fc7f1087fbaaecc2ea978bc2dd00ffa65a410c0006bd087495a8a8f70ba2d0e6a463f1ef0c372707e0702c29820157c66f1b401003e5b571e48714ad403be51aeef3c2a359e01ddebbc85960e8d037f7a133b84001abb970b9fc2f02e3f6c91a935afef22de2fe46c13d9702e263a63333b38e7008acd16e4e40e39ef98072d99600bfe9a86d80a738b8b7de1b6fb59691905490031f6960f05b859461d39e91d08854baaad0e5e78c2b27b8d520a61f4eaf5a0001cd4fb26cd93dfe0f73fdfda0a5f2542410ba40a7631b2ed624c8d73721aee00fb6fb41ec68deaa90a2a34610bc97cc46c0dd372e4491d42b1f634c15678460098a8c71e3b25bec493cbea5834489c9db4fce32d1c0c452bc042f7d56af95400c14b52070a09fd5bed5bc90595fab97531ada6ac9db6120d4c5d253db9e1a90061bddee82bc9a663a675043a72a03d569e08f83beec3c2c07929b6b4fc26f700513ebf1d67c85cf43a96e15dba2b742d3f70941659499e0fd18ad98f1f613c00aaa82b75d5b900c3f0c35e2263884c3f913ff21703446b589490ce68d810f500748d03655ec5a012fb27dd3fa743e4d5d3192ad6e774e83e6bfb072ce9cdd600d58b4f501c26738b4e4053efbe18466c960703fb7c247ada1dcc71e0dac1a300eb4b1359aab0e7fbac93ef7a9c82b3d35702900f7fdbebef662cc2901232a200c7c53171cdcf2f0ffd11362a4217b25dfcf6bd1339ad7e6e3481bf4ccbd24500bbb3f7ee513f6143323902ae9e7679098426f71c0d15def84904b836ca17e200b4e278088093ec12398fd8c6f002f3fd4aed201b2d4f7da845b654411c3c7d0079ab6fef4bfa73a9199ca5d1f30f746d667a01e35a034e2b10c40ba507ac1c009cd2bfd92839f12390dbf3abf7eef89a80f05644d2721f5020ab6573e2382e0070b1a51182163235c342711c76831c32253273d85fe1ca405dbeedb7bcc3510048f84552cccc0110956c6ac2b60a5eef2e51edc60c14abb2580846c5b1ff0200e38afd9040799773b7e1db9a5b97649a921ab33c5b7d56eb28147d9bbc7553007b31809febe932baea64af37672360ba7474e3c081136f0dcba219721a3fbe00b2df2d23d73badcdc3eb8b89c5620fd19da881ee1c57deecb2ea0779ff694d007d6c29990cda595db7d43f1dcd4f0475cb480a0ff0232c6917f83df4ea3d2000ae64efe69bd5d5b15a2eaf4add2dd12e03154ec664985069f62b0cc52f230000296dcaedc023e7a8ed63421dacebd54ffd1163a476e3182b3b5bf19eadcc9d00a04f57419c904f1f3abfd03e8ba517284ba46564227a073311f03a9e92bfb80084705cdbeed90a87ee4740b4115642a1f4b83ef5bbef7a14123045cc945be200f86943720c2bdaf238275bb3c1c38f50298af851bd2d39a3dcbbdb28d0b3f200de9d131eba236c4de857d16522b31ee9ecf10b5caa683cdfa34199f427334e0016a3e0781cf70768f94e96a55343e7deee49b5644f9b539a778e7dd4b25eaa00b6af33563e277ceedbef29391c213de78d8637a98a384463a095d14e7e2455001c9a0ccd1a46c635ef32fc88b7829b4245c024eecc3322cee717d34a31f6bd00e63cd5725e77811d664a0ccf98b04968778437a611f4816f1c0956ca18210a00dc5c9cf54cf53ae382eeb74dc207260f7748e109449c6df071b353fafccbcf0064369c358ad58532d57cc00acfb1aad1a03d4c6a418a0f0aeefc2d64b88c7200a7a53775c4a99dbbbc1016a605f596dcedd7a2defa01e132f6e279a20215e700a78def9cd7c282486df682a4c1a25d9e315d6286b40ec489a05e79ef4f0ac500757d34a97eb13c597352b5e5d73d821195d6f03d73f36072fc1b8a2aeb0d52005ed3e3ac6f515c531513f89b96c8aa2b409b6180a20c54a54fd45debc3d5ee007d87198ced65d6fd454d1c993c244e742f46e99ec1600d9ef8531d879d9d1300177b905543187667decb3c7977b40c2b367e8c66944eddcea941f771710c7f002ea99f98a18cb3b0d8c7fa95231b647fb46b439ac5e58d469606c9ef15726800a238f0ef8feb41befc844badfc13c8737a7e6fac8ce6f73005fc4afb11f29e00b6b3f4e14726e000d57c6f90e8397b1857a35d52f7f6882da9212adffba30400ab611f01e8a55d80f700b59fc518f02751673a270290cf4418770e1ebc0620003cffb14372ebbfddfe0efbf474a6313c624b02dbac81dc78ed8329f4184b44007a77b46c47dfbeeec62efe771cee510f4b4d643437c50d4f0df783a5bbb0910077cbefa9e01081a34c2236870903b0e51abcdc436e305053bd2fe9984d8e9600d3ab17af7c1208d4360f7555f2ee4c4104719095c0f0693585c6e2ea3215ca007260310fc5984da7c8f1222f19e9c5de6b69789de49c2bbe2fe665b58399d7006beb7654d2232bd2f0508ebeccf13fa68523428ae8ae96849b75c054b39b7400705989903b045bc8896eda0bfde0b030ca66c686cd585e8a529a3799f990a7004a9f801aa546f1ec14a9b2113353d758cbb4134c5d43470ca676716671655f001b658a4107673b2d1e0b5ad4fc56fbf8b7403574d05d9e275909473140ed9b00d03cd10ac5e3412443643ef9309471cd7f83f71235d0424799ff4235408ae800faf36bab64f36ff7305c54abe5e4a5d6c567d62e95572ecedcf36e30d481f500b9591c5042bc486659eed5f735b95910abe23844d07732dcd4de32b5d66c2200e4ee93d6b029c6602d4e0d8af0465061c21b720d92c8223061078d0c6181e3001dde01d11b1e92d1092c41085fbf4ff6e90e7539b1db1e06db5557fbfdff8d0051b10f4251e78eddb93dcab18dfd1a24e7716773c86f9deb2194bb5a636fa500844d6557443fe38940315ddc1ffa7dd04f3dc86c35ff9ee1e3f6e0b2dc04c7004446e5d1ce0a141886708a382904242486651f33f3cb3e62112120af77fe8e00a5eb4e5cafd61205afeb12a927e8bba447bfa5bb9f9436dbb6281c0a123b7700db913dfc5d633488019b8903f063401295038d54d54317b28d90fa0f943a5400ac0c571242832cec6d9f9a4015f8e79437d621132098b0da832a06026c54490065be568b132e195c9a59811ad2cb1a52b0af87c3b84787bad801957ff1937500bf8c55a62d74d81f1cf76af322fe0cd2f86f7e22d2923350e3bf7e7863d9ac0058fc791bd1bd7450161765b3c718e8beb80d38ad9805791e979e0b7f12619f006a97d70f9f54b09c8ad6fee827aa3287fd3a57d2eca0430366db497657beed00f4886436f3b9ca85ca59ba40d35d2ab775c6cd70523a75137c9901ca9df337007125b04ea8d624cbbadbf569521be8c0165cb0d0c26e25196a8c966e762ef8002555aa9011f230a2b475187a45477bfd7c8aaa0ac39cb79ce189425f2a2bd90070c579fe5a4f1c5cb8860b97259a780ed561e2c4226e09cc7a740121ddf18b006d7c5957e3126e551dde78535a271dd2d4a32c72ffe037b7217b816bbe030e00acc5a7fd5839dad78c1e5031bd1391187ca9aa020ec4fc42063e198202e62300afdd6a36e5fd60bf3da3a2e00ca5405a4e97871822602db2677cbb60cbc8ab009293a187fa86a48181352489d773a308cf3697354131d3b60ff318409bc3fe007bc3501a1890e87a110540528386f496a0d94ac728df74653c2c0b14ce05440058189c7bab604a620ef77c7abab742b869aefc0cc61f18e67ef7d2a8e98272008f500236736d54f988054d0a5bdacb5cec7f78601f783c151931d48eac5c2b00e0c54d903eaf3f5e70e538fbcd5f2639800fb6affb5f1807f4132a3cda10a100f9b9a0b74684a5883e0ddd303a6885a900ccc23b41d1e50672083147d4741e0032f87fc45d58ecb29a6c2133d80218d018d01a8b8c84591b4a187b8a41387200bb6abb5083feda70ccadbf18cd485a6af3cf0d751fadb426336ca2a2051bc700d13dee71ea8c7f852bfb5483585d9dd294ac4ab98329efe9e47e04e494564d006b36ca25dd087ccc522a76d9b777c03fb8d36b16843cb53d066db33287cbc9004ffa2d9534fc137ebaab5e119dec2a49faa3632ce6d3723e1e49b7f4f0d3860070d55556cd6132435253b827aef6d0e72fe50e9aaccdab1ae562bd11fd91a600f67346efd3262f6f3cbe925ea84a474affb4e38902c2ab1fd5fbfd1eba4e010082d6bb08c645a782e6b48a4344b820a45d81e526c2fdd78a6ee1900eb2014e00a9a45fa46495f4d1248b916df48f70bda92f5ddfd5ff3da89b81c7c8f07b6900db0dc6ee504d70b7de56a4350f997cae494afaf57511f3548d36752beab9890060fd9e2bbc012986d6aef749e242607dae4b94316525612a7ab9b599071915003ec4105e00dad91369fc2b3fa80c34346777664bcc59c6a4f2f97cb2dcb64b0091362116ea3b8b48c12b2ad268170a76e71842bb3458064bf6246438301f3f003b0ddce4d2c49fe90e0da03bd796a7d1d19b4531cc4f9db7601a2a95423677007fbc3aa964d4616f3142ce2e6e9374fbc58c3921ee07129addbf68bf1cf695000a6330e88148374df3b07e4702e829f7ab1d87d735b3cabb3750e692c0a0ca006080b13df801c286cf6f2a684d0b48b761d69d5e21a07e0831213d0800e61200f5fe8536cb6fd8303ff333ff4b5180ffb19f95b40f1dbbf6c31ef497877f0400a9cf2531127317047e6a9c952cb878dfa005871f224d2325f924b92ce1564600785957ee33662f6a3fc88c768838dc57d1678eb6dcb7aca021da280f680cf4003f4051bd9a60afdeadbcbb297c841a22ddca4c866054e90ee28caa0ae02711008c0a00a61d73f30a2168bca29764d4e8fe9e4fe5cd9a7d68012a793b064b01006a701714549c4a93c4e7d189ee739d80ad5594904f087a43762f0b066cc52c006c98e626158c52fe3723fe085b27e2416e41d831f01a74f37b6047c54a2cf500f2770017459d554cb836817d4ec1cbc022296256b0995ecf2a8d7bde5fa9120044c637565535d844bf051787973d08f7022384ecac55343bf246185f603afe00685fadc30639d7b182ddd8148c0736b490d0ec401f8ca8b0a312d64ae1c32000b3b60eb4ced4c431286a9c5b12399fab8377b776498bc9d868144359553d05007e1fd6817e2fe7ea0a3a74fb53144131ec3b222a4461801a17f1b3ce1687840026124adc8440e83883facdef6ad29e407c266602db36c54391c3e3cca1348500e514d2859d6aadd5a69a4f20f3b0139e20b78f3ec80b7e9a725cf952a8513f0099271aabdbdf7fce9a4a78460aee57e8fb88fd4d4ec6e3e24c899aa63d8fcd007003402c6a1dc66a134730335d2f873bd03dbb8448190dd2763c22b33544de00cd09e96b4783d37cfa15bbccaf4e60059f77424f5f414bcd78d2f88270f850003f38afccd74bb12f3b44c666755ee217c1391e17760a54bb461fded5fdb31500c6fd8df0b5c4e6b4230e006ebb6ffa9f4e539c610f2269ed93043014ce6c3a000f75b85504dfa711e2b9604b77e67e6180246ef848ba684194e88bf118e5e900d1ed3951beef7b8ba44339b43650a82543705c00c1274838ef1c5e2d57e9fb0009e9406f8161cf6cb5908815dd4044dad871dd16e74cc846cb46294d3a5d6a000aa0915a25554755a4496fc82bb7575551870c40bf791a3462f57ac00911fd00dc129b7202977ab2943d18b734819a4662e73a3e0553c4d6b0778c92c3d53700470f101981290cae511f9d5ac933e7332f77d863f1e8e71e816e77f13e139800a93f6f034cbf1561cb8407296ec18d08a990b5b417a8ce29c14382ff6a670700c1c19f3bd73fa4bb6ff7d59c33fd0d65f2a38c3387321f9722410869ebeb7500419b9600235aa3134b56b12b35465a8a06e7b3d65688245ae843511336a3c8006dd4129bf4cf7b9ba7db1c8db0f3e30c49caba2647b7a0bbde5d25341c7e24009598f7828ffea13bd61d9c70bda8326840f54f0a8af4a4324d645774899caa006b7f1deda86885860722067b3345422f19f5b14532f434d706b8206b14b59b008803b6bc75bc7535cc11ffa18d25302a4289b1ca6d2b8df2419d0eaca3854d0099cc0ee0b97eadfda733dac3f74b985de651e8d4a77de5a8fd40291d997ed300c45bb1678883083b841167054be6d7ab27287c09df428621529bb57a9999730023dc259df72e55b4ff39e54376c589f91666409ba215e894ae1d50e480c3810000261855153d1ac83f2c8e951bc7722e0173c18695daa2b7946559ff44f686001c57c6e2ba7f3e194898e98b370ab55b253a775037dcb746efd638480aafe700ecf6e06f24026719e77707f7e36ebe42ed17be0afff2766f7f95be79d6ed680029057048be0005a8e46baa95f61f59d29379d7f5966b3f897115ff21be651b0065750277430c0968d4ae1beb8ddcb6ad63474b03897aee08c41314ae3e9f7e006f8922959464fc83e239183f7231f975b77ff7be4afd0ba6ec6eb91e56976400154b6f97e95897c930a9ce2fddbaac77c12ef4f623239e8aac4cda8bf9378000eadc5ecd0b8cf193571ac0aa789cb7ab0eb59049e6771f5b8f9b87efa4eacc002f449a41fe94647333b30a02b5320a3b4fc3ba05be18e701caed485d202d3700158e6ed5dafad276b1219e3e712bfc7de2ab1b5c91443081cef2cceff6c5eb0057096dfbe5437bbdcaea05ab6f7018c2e1a88faf13ea4e723d9d753d328858003eef5755f7dfe409627c8067df30775ba26de2b53e0f984f4f0be482b2794e009dd1fdab4bc2d034eb81827ff1bbe7b00bfc642aed11c3177edba01f0bd3d900ff3ffae4b4987f376b080d4271d3b831f44745134ffa8092e716cc5ef6face00e49b5bd5736c1d5430b186f9a2fc04590f8183aaa15680254843ca63d91cee00edba40fff4c4f226f77726f95f4427a5b3b7dfd5d1b8db39bbd183484a0498003af91d6ef2ea6bf3e6e2d9a74789cdb70bb30de35265506d62329a82117f1400e7811236cc9a4d7edfc1b38583e39c67aa50a645711209b1fc81c40095d3ce00bf1d79c026934f37a0fe47189468a1ede96302353120c6eb267ada189f6e26003b93dd370a2628e9761c0b215ec90359bb3479f1194bd37cfbcd3a77ddfe9c00e2465c6185bb5a069846b6c8f384e1896cacae10fe94f471c8b5fb559320ee007cbc6121429ad452ba0072077d029bf9da0315083e012740ead460531398ac0082c418ef26fda21e34b53e774537c9f414925e0156026e2e6724de4078cb9e00c51958606f8da99a295f73552961042bc230729f04872726c9ece810b42836001433df125fee8aa5768417bd3551105e450aa579facf0f634ee3b0a5b17ec10053320f69785af588d2346bd549f2195d2a4e0c6475e8f68bd88c2ac10aec8a00130245a91dbeb879928b86e195b704f90987e329cb12f0f7a588d56e9c52fb00d5332a97b0ac1e75fe0ae7774a9ea785dec3f35ef96274d0c66a23773569330046dc571524b280f30d3d1296c3f0d90b80f4cea8f4e0df672d028026164d5b002035a91d6047d24b6be03fcf7fb130d9a722dd4f62479429e197a74d7bff54001f9671e044384bd444daf2775a08ce318b6eb99381f610632da2ae19aff5b3009edb41f2300441e5d1ae39992f2ba747d40668879314f8edc1332a876ead8400e0b98508355a4234987575507b272540139d54235c08d0d49e75be63611e3a004df272f960c37782230f9cfa89dcaa9d7016f545bb382f5135c80264c6cf5c00a1c64d56abb19306f33ef22a6d6ca55b919ed9084cd4cecb01c426061c11eb007282a3514f6c700da6c8e247610e1c95816b457de09fb102487f836d9e53d000455eeffdfacb10c0707896248d73f8332cc2a2cf1a2b4541eb9c474b8b03dc00855c074354349f7d027daf9d537cf3a9cf6c1fc9a7f69b7781d671f8ab3754004061d3e3adfb7660de7d18bfcf1f32b30b5b020c79545b4b57cfc92a3d0c3e003b3981470eade70bb2e97c961718917f7d8cd78c2c77ac42a42cf220738a7800c009da89d59218f467ba07eb9cf5e71c4b922a124cec14f4e38638c9168fde00127e221d8ca500cab7e4d9284e43632c95b6a204b12c7a8e1d62e2a2bcb3db00a23e4235e2d16b7489ee4b5c7c2fdb2a85d69796a911ed26cf1e0ae80c75be00261ef445d434367424aabf6e7dc8db3a8473ed4955023caba97b29c9c3a2f900a3214a6088632f746b653af37db96d9e1a966d4ffc9afac0a046293482f50b007998434cd0ac32858855366607677b1f3fae24ee595eb6f6064cd5946c66c400a4be54a2f24b837e75f72369f1f0fcc664f3f7421acec889a413e3a3170b1d00cf278b610bb70bc104aafac1f2959717a902ba02e92f4dea669b2db6aae7be008d088412f6b527b40754501bc8e49ed26de9da156899f5dbcbd5745867eb4a008d13faab90312791a4047480491e74230997e632ecde6f1db51b79b47ad31a00d054c90a03b226ab6c74d4d36fcd3a77e0e8244343ffab08a0a866d477355400895819d7279112feb132ae8e2f8f934d34d0d39fdfe908991604b08602de1100e7238eec3510db5f8e9e850c4cbb2ad61851c7ea675e6b4354ef3c4edd09b400200020bbacb4793421deac326aceb7b0c711dbb3a1e400b4eca15991bd9a34000c5600513a2c1bddb9ef73b6618397406ae93471b511d253477cf61058be0300a1e11b255f75e00da2b3999c1aa214d9b4cd91e5621c5157861e6d6725dfb1004affa647c9e61812501326f66c002907061521a67db1173eb6a2cf62381ecc00ce8b40afcf7b58e41734070c1f4c8b849b49577d52b857138f248af0db44c60078ebdd7544a8c230efab88b4632252667a31255c9e8e03d4fe36f669142685004d4c43a0565a6b699e1f7cf485337dd10cff6d230981bc759245f51b944875003dc5edd55d706e4ea7b956dc960cd78968bcb7cda8723513e5f037f0b6919b0011dd23ea57726b2018947c6ff0bca7300f29579d1bfee10b86dad740b634fd0047f7504f8ebef43085f5514c799f26e959f295f698c48766405fe4a993c1ed002d3fe0b4bdf2e4c89a034903ee7f390b89e0a045f9b6de33fdc4d4794989cd009d7a3e94d0efaceed9218f0eeef87b42d63da8db31f48e67b19cbe8452a3b7005eaac77f965167a3c445cedff0feba7b20a6b6cfc578fbb0d4667f08e7813e00d02d1155d862b4971a3dc7db6f0c5c877ad6699ecf2c7510fdf03e686e6cc00099ed537ac51704d4a7e150e764e259e2ef7ab8ea5d0018e86af5d2211bc491008af9a0103164c0869df157c9bdce67a364852352abd6cd64d5c886b0de14400007c746848225ae6232ca89b21ed41d850210802f398a0bdd32fdda4b3c2c5300d17c4026bb86b03b1e1835e4faf78d70e63c9d18027c1cc225ff837aae088100d6e6ea9b4e7a8fe1523c7fc4a9ce7105726a59a885c5fedb3ceb5692d065fa0015371ea441c01a5278739812359f22e4dbd1ccf5349a6758acb9552d8f2a3b007c3ecb2d615bbe75e5a3f9bffe60da133a6527cd5d04411c0206aef84f0ca80001ddf58d99ef75406767bba5a4542835e8039320d01928d8d21516b90715ae0075affe226bb59e2a6e7f780a0947b4807c76722e9cffde6e35b0c026c039550040c75302b9bf5030e29a91b4fdd84c454599e7bb9ff8555198d5bae507247a009a05a3c370e3217fa7126d073e8947601c83fc78768e98c1b8b02cea6ac61200e275730ac955b3e5f134f42404d30ead3cab69988ea942c1a99a85c47e21090013a9ce37a914ba23782d0853faef6f529e2a6148c5b8a8ea47713822a3bd1900345afa32a9f063c4ba996e96ab78ffb59f8ee2b9872cde16e5b54a3259cd4d005d2d4fe8c96cd4d7cdab299f8ed318b8a3c0adfea5351291295a48dcbd7816003e9d337e128bdb8848c265d4a24d2f2af8e5ebef58487bb2b48eec4dba32b700044157a43365e14415ec41e575091af9059d45b225f5f1e65cdd6c6bd95dfe00d8e87e8d09c41854029f7483b47d167bdf8a45e67243e43ae251a2377b6b86003f42943ba6e0a6c1053908c7ec8ee6d18448a1ff74b353aec8e5a2e1f0788200a4de52e4d14438a4b5676899d2f0b16a4829b85f95c503d522052b13d2529500739481bde9bb0f199e6634c7bd81dc8923039d7ae43233a857c888adf5084100d0ab29d1c26a20494bd835d9ea8580f3aea510a0865520cc03bc223ef46e5a00b84b94d75e2833aed977c5eb2469e3b8d00520f52ed339a5b32fb318de301c00f94ae7cbbbc4243770e3b0d8dba49602801a4b4fd681d78d49b77bfb987f9500f584df73f3d3c997b4c8c06cdb82e8837625bebf5b112ce2024426158c085500dd36a336fe79c10a83c90661068a0634ea55995eba249eb73554f768794dc7004a82e0e49ee72c8c42093b3cae8cecefeeeb4dadfb486d13720ba62b0e6a90009c6449b0f56bc54e690d49ec6ac59440819a08fc6f85caa0d41c1d50d5dbab000e16a07c1ee3dbec97116d3ea398e1719ba688be8e3f5f6160e1bb1c60a5cb00524c4fe4d7daeebdae17203b99c167551e720a77ddefb6a7c7d32df0c17f9d0030baad203d03de456540aa8cb59b0d2762ce92306e5a78178fca1d81892c240040c0250ffa4f22768dc17d34981373b677b4d0ec3a96afe54f82491885a6d1006afb14ab979210213205a17109321ce6ef98d63b03670ed4bf426e887e6c3400dbe2243666537aff8513ad7f6079567152e84473bb4c87dd4e860c1c1be38d00723ca4dc7ef1e12f95cf639c910ef6422fe70354809fee37db7210b0c972d9001fb73dcf7bb0b5fd231273fef6507627dfb50a0a983f626d03824add7bfdcd00d8915f1655dfa8c272b2234942fe83dee42218f6dc10d548125400445ff0b400d1e9c187ef7d956f4a58bb94589a8a49bb1b5d276ac34b8359bebe356f340c009db0e3352f7f9d1448b07013f5c251d3342aec064894d5ed3a9fdacef6edb4009fa3a188fa0aa359b006ccd29951ee240755a5f981e31db9d12f55c1ae1fe100ce7a113625424abf132983ee5dd36fe6ad074131c7cec5ea29e0cc1755eb00002b1e6d2bbc8a25cab19c85da20365ce74716f43865d3196fce911a49f1e25100028b7de13fc550a3cca9c095bece3d950145cc276ff93e45e1e18606f0a76100bc48f658578a2c11550a3e9c925774f3545a561c700cb17041cc6159f2b9f700f15d1a4ca0ef6efc9d9193228362aec46bd82bdb6388e9738fcdbbff67dd31004fbaf0869cb073eac20791de1d4218901892db3af73dcbe2bfcf4b50ad0f4000f282024d9ac89f88649ed6f6aa2d877091d3440490d789f9fe8c086aba65c0008a717433ef16166c6aa52c67e82bca52cee3472113d7e850fa70812112dc2800d9ece246ac1e68dbad058a838892f4558cd72076ba246975146792510eae1500f489b28c2e77fb80e06c7ec1a9ae740b6ee890b99f583f2a65b5cd9a5c168000f63aafac1f4967a0a26bee4642e8c8f60cead70ccf1e5af086783dc7b597a500adae47f5f7c22dd8e797bb5fedb418b0d35c6533f32edbd959f644c62801cb0074c85bb3da42389577c69ee0f0ad8ee8849cf76d8bfe3d7f7317b48e59eef3004eec2db00ba7073bc06bde933baac44aaeab8c00e148623b9c68154bcac6f000a5285dc99351557ed582ccf450ce456659d06f8602a0cf0da7cc3a8b5910a6005a388451792957da4cef3e486ebaf5dc63b43b15e65ef3607a2ef680e3dc2300b63bd2b0302608da835a696e013a4996bf4917d3749a6909252b0cdaca7596003bee7e5e5121395be7463706f51a45d57d7d579a423ceb1e28360d46b1bf310081aafde00f9823b2159fbf3870ff1c6fdbfec25e18e93dd5e51a15c12c862800ab2ecccd017d3fcbaf01c322ed6c83ec17a713528ada5d03065b8906be100500a69e23b55f70caf87c61d01a7443453c6c0f30378ffc907603a8eb608fd24400f5d305685a19da9a3980741dff89714407143cdc4bc25e1992e05ba80ccfc900fde77cacfcf882eef0eaeea51d0bcf27bbf28fc4bdbe42da0fcfec827a85f500a09a0c7072475aabb18a44d71c9de3084c1b05be878073854f2114f544e0d500f150b3a2c91a96bcc1c10593137869bfedf6643fcbf87e711d7871a392d189005a0e93590cd5fe7cb489f45a469fe9dc77d6a8a3973bf08b5d2a04d95649f9008cad0188b88288577443581bdb75e04a2ac6277e73b80fc1c12b335694803e00142aae70d1e09f78a68d5f47582e8753db30895992c2101332689fb8aacd4a0069b6607ada25a7edad09e69192857cde8d0af956a86afe04a673f305f81c6000c0164569b69f7086ce15ec66a2c96f7c0b09f15a3ac8eca1b725fae33a9bd600da1dea35c3ddf01c201e8d09e03b5d52ec5c95c02ed92c69c6a3019f5630c7004b9d68034cf0172fccb396a1c805bf280a4b3b7954d979ffc12e3cbebd846c009ca254566c5fede916f89cc334b0b62c1c2d927c6d9c6eb8d223fc911bad37004c88bd04e32f82b226e848998147cb3e508a0cc308b95ac2e957de164ecc4000e607fe3e0b97df98b12003e80ca374454aaf6d42d55ca8ddb423ff406d011e006cc9ff1686d97b38f24a9149b96d8336710f4dc050d88441351f4bc5857a7a0077d08b37e7bdf2eb8edc585cf285c3adce77286a916fa23a1cf05a14398ee4005639c49a2fbf40468962e2972948fc469911c66c173820a409ae8f937868900023b08d845fb3de8aa9705a2481ccec0850c4e5d1200f732f52844e600c955d00b983d6b93199f9ad78c0755f5ba2a58ad0955747f3efb2dea819503214ac1a00599f5b0bedc005a49f9822053c0cbeaa092f7a613fe977a38ae439bb15d73000b3a6aba0b53997688181683d3fe86f1d4f86c730370d029fc1ff3d3ab475b200e7c5daa6e4d042d93de0983e2d701c21f8ca4cc9890d05881b2553b4617aa80087472003bd5b253a8b106f8e2ac411d0e6c52009b101d5dc96f17e08e6569b00e5865af3cfc331eeec404a908647c6960cb55d91e9e5ad43b3cc6f0868ecd700e141c4a76969513af32db84e25510b0307d784217fd3d04e42d3fde4eb0beb0056c830a4671d5c6b383bd9033b3931fabea2969a7992ee54acecae72a5562f00f9f0bf51c61f60af6de51e47dc89e27b7d5f263f3580321c02bebdfcd7860900152a83b625119564602d20e5c7eacf04dd540b7c40139f7d286c28c7449e9c00765d4ac80a9a08380b9fc2d2b9880907a5c5e2a9896224957894726d35b904001e48aa68fdc32a2ec6a39148b979b256187a8657c8cefc13dca1b5240cf5c700eb57380645440709cd76a6272a9174d6fbef3581332a2d9a8398de1ef60eeb0028b716819fbf7b02072f27de27c43aea55f05b595a3b696af5edcca776049600e2af2874acb95052a5c24d76fac984991f7db98dc5abe2bc5885d3917b54a2002af75adc009c4bed7433fc460684f58871bb599acd8bde5d0ee0894df8249e00c7041c671a6b139521e944b6820211881f84e0516d5de7d79f8a61a3c480c70089eb0a810415c21d644866f4b330e1c4f94952fc263148fc5556cf46d9e1a20030b309d6799da58090740513f921976878a08b1502a994418f6ab075be974800c7477458812e994f9ca2316ca76f74a4b18a56e7b3df8c2872bc6a85b4cd4900647b87a325a94700807720531b5b8ea0f30c2b9b10048d08d21e8db5c837b00082848e8ebf8a364fb50c924717ecc5269777b53c4e0f4515d90f1d9538ad64009e189f07cab37c9c0ca9f9a44394a706f9fde09d24e392e3f0ec822383276800f58868116f0da8aa9891af141a9bc01f82b748401dd5f9e4965bcfe94424ad003a80bf5df46d3b7eb0cced1e11f881ac22956a4f24641b3343518904d50c8000a8df65b2459c986cebcf23587cf8b119ebf8d6e5d5de041c79e2bc01b4645800da25de1a999f5973eef0c35b19efc0d8d97eb990c14a2127b69305f5c0074300776b8a8a0c186de55c6c39040a482df4b9b8a961696544f283ce79215fd48600d374c91d18d90879603e9c5b1718a80c63046078009243ea2501921cc91209006d1f10416276efaa0bb6378a03ea0461f18f9e6dfcf13e1c948b200cd99c690088fbd6b678edf4b16f954b10bbdfdb1584d655e3409bf49bf02688b52d67390062459da5d49ba16ecfd1279cc2e62ac3e17b3c8ae6f9ea56748a1a98cdbf550036e54b909b22bd5379a5c535cf0d9d044b9eff794747ae911b964e4022421c0028d9212e0f20ba8b537db7c378307cca31403bbd8b5e6f9e7bf5019396fa2c001e13755a65ea73e809ab71976d1cd4a7f71f98f80738d545346d4e8392570b006deae09f2131cefa9f0266b8990eff47da8e0326714d69c6b3954a3f3d0a04007547c456aa1623ca2d41fe5bc34378c58fbdc69c6175cf3f7f9666369d9d47009bd6725904e019c4a6571cf5d80d139a0c2ad6a5bae60ddefb6e7dcf20259600ebd405332db962563b4b9a127385b0e6fdf0c242f881ad9ec64835843fa86d00d2b6ab2eb2aad753bbbe89bcff7a0f501b19daeb682531b05fd1c918bb26f100fe896b1eeff9330394380ca39e65f455c4f8a938432c7d93e3bab7420a7ea70072e72afecec23df17e0dd3cf67e49bd7d79ca23a20b5896dc70c47a18380c8002078e50bd6a35bfa34b51209d46c5a4d9e3de761350443cd41e952ab0e2181008d7bee3721e2db3311c6fa19ede89704d94acad2fc91bce498978f00fb894900b2b4a800f55b6a328ef0135c3c58d3df562f589a019fc6de2a538ec966e156003d527bd51a1802bdafbe538cbd6a80a5d30ba04f7298b64c618a777315e8c10072e59370ba60f5752061e2856a94ea921b06d9fea029c1636f9522f9362eb400cbf46dfdc0a125afee14f0adbc597ba0622d17e7dc2d6ae87eb3d4b2533aae0079473bb726818a56951dd34e6ec8c95a5592f5faa6fe3b6c26c8f0feb8b4d900e59bc85d2675e21af860b103f1619008eee8fe7491bce6157e7b50bfc33dec00e8d3f27e0595863569919669fb3722b5aaa9f0ecc9ec71796c2013c22e49f30089ec440282ea0568f5f3493280db2c30fced0c3c8556d07ee58dc7cf097a050098da822578940102114739e56fe4919d95a1c9cd11a43c2b08e1f457adf825001dc43b5d9132aad7677efb444a9343737eeb87fc24f0d9b5c9324d1d81ad2800a2847c3387eaef5c78800fa518dc743a80bace9b776b3559e8b53fd56fcef700ae3535dd172b10c47449f8b55c5c93a97595f464bf977f1fdf1b0a72404e0e00ed2a755dbc057d21bbe6ec60a363f753904094cdf55ab77c1a525bcae6fd8600e963a149ecd95bc8a9b4078b076c1e57532163ce970b3ae630ea3030facba200e2bd2918df31f932adc33d8e0870152d978be331d231276373cf281fb78026005f26d6f77c78954d70f6da1f7e3a4da81acde19038558c13b5ff48a85e2f0d00a467bf59c4140b6eaf1567ff474bb7414ff673a620addf056d60dd41b6c60300aafd3f9f541561534d3ee456276b692e1b73d70a8b2f7b8737ea3adf22747f0065b7d357b4ac1eddfb337916dc67a6343bc8034dcdc68bad68a6f1202b63380000156d8fb737dfd83829474e67b507f5698dbda2d1555847aa9201cc2478d0008a8560f2b9d9d2989f945b86230d68dac29c3eb1fb7563fb6bd0c07895a4ea00c9e0640552a53bcbd2e56ee692e92ae7dd5849509280836a050709ffd1a370001fcfa9efdadf8ee8f3604173145654b2d6f10d8c1a04c551bb971715d6f9d80099db01c9776a16f9457328828156b2370636da01ab23cad52626583d20388d00f90a213675169e97acfae8da714c1c5dc0bbf1ccd2743a30ccb0ef7864f4990058c252ab67156c28d56c9c6d6b9a4f8f9064f6c77a4467c93b72ed144711d0005125599fd0d1e68f5cbaa49fd11ee3b2aaa9fc55635dc64b1e7864d2d3acba00fa94148ae608dfc0d0d134c3a5acdbf2912a58b71bcf9c36024fbbf2b283fb0094a2e3c3766b9dea7ec27adcecf20722173afe33d2a9fa4769f79f34edc0fc0035e68bba6b2ad1218fd7b187ad509a10f2f6070497e5a1f59d7476772b2dd400528f7f4e8a02908fa02c287e41708bd04aa6c241685ec9b2595ea95f74abca0095b827a448d5f22ec33b0be796487b789fdd7a859a1dfc90142fa0b47435d5006a2d22d475983c43e10a3debdff46a545407969894fb19aa11500b8cf5f9d600f856c634f66b6ef79bb51bbfcae3705a622be8c4710295d792086bf2816cb200425ef640ccba8c78be018f3fec6694ca5a67a9949a63400a5ebb7712aa382100de027314a77bdbcd50009056e91736be2b511ab0cc170ab59d7e8c71fe8cd2007290023011fc15946daa1dc9a1a062f1be77bcaecb26643aeede5f296b5c9d0040bb8874bf6eb685ce21abf61c4e14b1ee8850b37b41c496d570184be4c462000eed13a3f9cc166a54d6855998329ca9f171655541a3735145f622cff6b57300f8e66bb72faf1b2235579f9583f209e0cc8e0b64bd70e0b64bd539dcacf3ae002a993613bec5044e9d7a2d364a8cec10f4914932c522b7255307e42c62aa6900312f1043549bb85d1747fbd11661378c9a831c0901948eb5a46669aea4500c00ba409b738714dd9db2663c63efa1ce73e4258c8822cd69f4b4d6b701123fdb00f12061b48574a69f3251ab864fc0dbb88a82de8c3f2a3581b8cda709d1e4af0064170d7fa30f43833db08500f713944d8dcd5f1962eb5f9f1a7168d397540c00397a68346377998952298792d4da3d0a2006f7d5520feb49ba43418c59cbb5008ecee5be27b70c531d36e78fedd7048f944b639efad67f8b0a70989450014d00140e1dbf6ff7e39786555c4f8dced432c0aed2f501f5095cd6e1b54daf1632008a08a64c5007c647ee6e15c5df58986cafdad3d4cf52a26e4510c40fd3dc3a00fb20882abc6f09bb164fdec30c1ad0381c3627da238a2190d2043f9eee328b00c2db084ba595aacc682290ea13d9f7670360ca1be3a132eafde92b1281489800310ba9979dab701ccf735353e3100b5779b6b512391bd9eee0ed49be60f12100fb2725a47852e47ed26485a733fffb9d03a0e740a23c36f22c57a687b8cc470067b4a80b1c9c44099863f7292ae4188f7f824bed026d51335254a1fd9b932c009fb3347c8d321e7b19de4a279430c43a1a50b15f2786139df6c8b8f31c42e5006a7e0e76abf75c2bf9dab0298f28d9f6a3824e3e115d56ed0b9d661870f55c00b74d287948c5c47fab01a87aeb684e267f273885af15043ac9c82ca69255b6008655d2f097252c96b83b8725874a1f8910fd411b368dfc5d2ab8f934cc542b0009aaee8691a7439a9758677eb9869fcb8678bc03a9610e3a761bba31e85d3200f56557c9fd94d32b64fa508271537500988922194e3632cf118b1e2b43c99b00674f4294299f526a1e9d1f410ccd0ef63616a886816a6e2cc02c6eb173050c00cd36d5d278b0e710c39183a22dfeed25ee3f2e742c68e610ef67fe4316496f00ae05bd8e559ae825105649580c0882582399a97305a88b60291d15d187e24400ea2b4539faa72e6a9670871115fa04aa704ddeebf7cdaddc445a5d8e9e172c00423088e6393c996553342b558b79b57e729341dcc306373806b700cfebac6c008d704977e4f436b7916eb8dcb04499b4af4f1b2febeb4af45c688454c0477f00b400479eb9e06f79140ff61da860f3d4a749831acb7ed751571fccae6e51990038621e6b2d94799b0508ac433ecd0ffac6d5166ac6348b87f97a2193dff9fe00f9208bb0e2cae15593e3670bd52b0d9f90ce8674516894f33045b9d06ca1a60030f4439399b0cb992303ed31afd90b882cb4638f6acf4baa7ec491406d0747009f3f7ba24bdd4948ab3e600e114451c4d5e370b3147811a58f34a74a4cc46700a5771f7c71848478f8e75ca34517268d2c229ef39263ced5001ef4f8ce455f00a5b9a9559667b0de52621b161aaac0135f6e8e2502fe9ca25c3336b04bdeb100427572de796edfbb183b0d0007134080644f5507ee56f6ea6adcfea753c08d0030f82b5ddaae6fee630bb652810fa3ab12dc5f4ba2176c44f69ff2abb65e5a006d7ed3a8d6a15c2077a811a1e0ef6f63e87d2b60eed58171c4bd89067a004f00b5848a1cfc07b79387082647f5101d11a4f20fbac814e4d0fc1a0f69649f6b008962a729e302d48a64f4c37dfa463d7724d82d13fd3638d2cf95c50b9fc87e0001877918c5e41be2a1b1628bf6929550d49bb62e079faf3a4a7243a5ae592400a1ff4bbdf130c5fa91d183d2f23106aab4ff5e2555caf755f99caf84fed70f006ab58db2be3f77ff5b71c5787ad0f0fc0eae1bc4a89f3ae62ccd6332b6ab0700b553e96d5a1b72d523d36636398b1ee87fa7919d3b0896db64614aebf195180004f9770b61a4faf2a86df8d8009b507b1b2ab9a6d8f8648d4b67073d1f065600b74e91513d61711df68d82ec4fb5b86ff25e31b77957b14139cb9eab31fd7d0098639941daab3a8e3809440849158e4e78b5a91c833bab0256f4426cb11a5500a266a17eacb0b7dc050dd06e45591ca8195e8bbd35a83e21b90c943bd0997b00fae84d6fb3df93c4043be7e7294c3fc6aa6975dc08ff9aa005f0cfb60b97a200d4887ab8079d3db4ff647d688f3930ae858e65b11e54eb0d8c5d0f4947122100c8efb22950fb671a8999ca4f1c53a8a7d5adb5b5bf961a0182cc871eeb7de200f72f773fd7f186f99055c18192a162c7749bb60aeae595147e0e562949e3b20046ac74aee4fdf0a3463e84c99aeabeb2ce4d8f3ba1ec1aa6f03c6d2242640100dbc73016695e980825ae1616f2f2de83a683f2d04d3a22ba14bb2fe0780683006ee4a6ea7c2f4b79a4b4434a0e9e8760ba75a5a02f2b36b67c57596a9abb190061b2bb4c440d049078c5fa28c182abee42b7d4ea04cf4fe50a4f4e7e6087d50067b0c08a4fb59618a95fae1ceb496db4edd651dba3b15dd2bc8c8ed962ab1500d5f721ca19010cdecf1ba0dc53ebd4ba2685494d0d6a1917031c8177591b6400ba7774bb465b133e7312e711e6b932650c3504d106896de1c64a2b59781f9d006d8115f0c96b7c8e68df053d620ad71bfc8cd7e6fddeae0250f6ced9c0294800a1a8ea55cf991cda5afdd4c109169c7b9d9d90397303b036c8538b86cf3f7900ba70f67c5fdfd5ac436a7c2dc14909c366f940c208652ff2c583b2b0ad79aa007195404f1e4f77213a96e5e46ea75541527233bc6f7fc998eeca5fe5d0b165006163eb776cb205635538cbc09593b921233e50cbc8bec81b117078540eca34004f3510df20536c19fb59d54f3970997fa7e303af0130234ce3604ac9e8fda5002e3dec038083731f3a88dbf8a146106719d166d6b836ae3a03050b1c6be6b500871d53e6560175c72c76018b31bdff1198539b3c79908a283a519298718f880042e0c04e2969704b33249d50f1d3c6f4fc26c93de32115847398b836d62e4f001f3ce620c1ed4c1ceb33c5a15818286b2ba73aa79841051e0bdd6b96bc0c550017bd20e36287209fed5516e4fba09cf65ea8c089184deb61ea4727304d8bba00c5e91839f84a526cd1775e1c266a5cb566a0c2b045b772f63c8a3e701870c0008558f92c0ea2c727845bebeaa3860d523f720f90faeaa7e38036e168c1186300e310eb5d2733e1119f8f6dfce9b3bde0e1b8df3c12547f1f91654eee3b858e003f537536d9f7d9f24f64f03bc9e540ca9f5cbb9baff75556ae92c59deaff9700c8dc91f0684301cf94f0f83c4b8295b37c13eb2cc64c16c0fcfd3b7c6cf8a10040744aa01e368053eb865b03ec44fc58b82bb87785223e12706ae991e9763600da1cc0e4fc72f3c6f5b0fdff49ab03dca042ac569624c204c0d9f413a0803e00c9a124cccf8a962fe32944c6cc20575179d5e6b831b2721d15bd4d2c1702d5001dd8e678c1f2ee237e21f3e865228def7b734ec4948ef3e64b8ba253b542ad0095a56af45da7a34664a80313ea23a00c41637fe13bdefdd5c585376088ab39003f063e3968ec031434600b5555f01485fa3f6cc19b5f941d3c636501b2cd3f0049ee9f81ebdd305cbdbd013046b20cf78e390a3a763fabaa2fd600a8316277005023a623b21a34c20c9f7f56ec750d081da000d84c1d3e34d4c328c460d1e7007ed619e12b273cc74399b42077572a24050fc709f26320c2a4c334ea12e13d00246a785419ba494d8673cee29c8555f1ddf9f3322317eecaab0f6a755c4a9900e24164eea6c4f04db10f10a1fa916ecb17adce028a9c53fdfe1ae6100b0b74008ca0f4dae75e0caf81c654340842087881f411848e0274be5c968e807a5b1d00684321360f513207e546afa6c715745a867271d9df8b2f373afeb6b4240227008bbdaec25f04a2c78b30a6ecfee82659a9b513d2b0feaa5cd08c02d30af7c300c08542500bda3f7e5dbc0455ed38f7c193fbc731457712e49457b7268ba7e30083f2a75eb17e98b2812b685f729729fa372b4b8dfbf368856d341863fb58c700c6238c75bfe0eba724197231056442d86aedfed57f21068d1ed09258441b5b009428005f75da8ebd26a507cd989970f4ec9ee674691f9113e089b875a0620e00c1d6b6af36e8765d577f749ed71528be2689f0d69c02f58dd2727c06da87550018ff799ae83f6037a15d81bf8131351c6fe2a041b1108e605a0db7bf1f1b1c007f086455d9f56e93c7fffbb2a46bc24eef8315755dea887a79172a702c6ba300cbcd72734f3ae18ca4257a4adf81d8ae95ebf707c415ffd75f76582af5f46400ff411d2091a64d4cf89a57f78ede1e4942abf27b65ccfcf59707aaf59f574d003ff205d324e75ac55a6d39ed1f6033eee04a745697532f0903759901619401005d7467d3a65c1d16eacf2701af324b2b9223befd73d6f8c259cf4e3fb75554000cb3a7a87d21349aa2793efeb18d717adee6c9f6c3910fce5b86ac932d3c1d00adf57e3c29204679d386045082e025b58585caf472105b3cafed3241abfab300614e5b7da77da0a40cbadd26f084ab3773b6eb383fdc05766f3606e4ed6f6a006be5b61e33c11be825eec691867df18f93de0e8eda937a930bd7b0c0d9bf18001ffbfdce490a59643b0c1c1e1592249242d22c285b524d1eed7c9fcff86610001fb35a149aac6945e9b7b1c43025b0e0591f27e0684f095b1644650a05b8490078c958b71a306ad3de9558de067cc939543be90546f80815accbf4da834074006c8a8a43769b0fe32b62a00273c65a43f7b5ee62f85e53526688dfcc20398c003beb7a601fe0f42d29a96f840186f8af0fae64948b45d793ee93c56366669d00059979eee01977be0fbc9f91b97df602d73d19be5fc2fdcc59febb5ecbcb150038245f850a4bef8d4b490abb6946ed7af15652b867ea531d905bb0a8952f8a0098fd71590e21c638b18cd09e0a9b232a037761cfd64c36db76f49ef6398e6f000fba00ecdea10007576645aa4fba87f3b77b09b5a4dbd4800c8f3fef5e90bd00f5e68489fead70fbae59a5a430cbd7c3b0abbdb86c77a9b4c494166d4932bc00a79aead746940dcf9f321821532c9233c1f169b9940980c6fc908aca306cc100a3c0549c1ed2f42b271f2fb894ea3fb57562a487b5413b8febe1efde4a775600b2186bbc3054786d58fb64696cfada9054d114bc94c1d0b439d262c4a5fc2f002b652a3310aca0d41062528687fe4c88c6e798a2e47a7be1d3d3738a31cce300d145f7042fab7b6673baf08f70fa22202d6cbcbe4607b7ce224442f6066a590048c8002e91896184c8054cd982178540c4a360c274a89392c5b7939d9933d600d0b03701a132c4424eb2227baf8d7ce0a0ca13cddbf9c27e4960a1f17babd700cc14280c9ebf8c4e649cb6e8f2b652942e8468ea25961f000044f7bf988cfd00b458eabdc8b6d15438647332d396de5c62ea8accaee1fca46e419a03f09f1c004f2be8b274f2a0be2a6467105d2a935498fdfd698becea63cc7b94fea42b8e00c852439f12e24fd9f0aa3168f04169e3a95d19ffc1904593eb59625ada68e800befe0fd28a753781afa6abaccc4ad36c13f05395acbcb6234e9ea4fec2bf7b00474b3b90de98926e42cb5de9e8e2d0ebfd4846625895cdc7dcd42cb3c85ffb00e00d834b018c0f8e67fd28f470584682df1b381e31e5ac4f146366905b8a9c00346064410e6cd3f9521763ab7f2710adb9caf53631225e6fc62a6b89a5684100e54d97db2cdf2182d5198d3dfa418d1f59ab5dbb35e531be8e1f8e42d3a13e00a155dbfc366d965e4be279246f3d5e10b3f8279b3e47ceb221a6d0d2957f5100e2561fe9f4fcb145e914271cb062c19021d07240b33d7865959460a1ab9aec009fb518e5069797a1b1a093fbfeea8aece20ccf7eb002c6fc597aba208f94f20058d782cc8b33d9ee5cb98f22c4fb30fad29277f7beec994941ced4c5f2db020073aba53046858f0d4859ca4830f8c7a0edf9518200ccf545e1ecd196352939007d47ddfa33002640435050c9138833b2d20907bd1fffc5884d25b33b0375b100922389b8ebdd8beae0bbb07312eac66d85f1685008ed63c2620da2e6dfe938002c66f06a29ad1abffef4669fbcfcbe32bd14849ee7145d4ddd053d36dc2fea0013427498e011d38f0e0a9667823933c2999eaffa3be71ff035da291da2e5170018f7865c462e2f8ff21a3352a54000c32dfbd234ce9218415c9543581fa1540038b04898fe3470f55d27df9bd83cf2d80868eb9935bc18b96f1215b46d7e3700146c771fead627598d2032be3ec98f34e3b4f5ef45305a041a6ef17afdadd3004d8988532fcfa228fcec966fe95b22ed948ec216b65160095e9808786a5fd6000e8ff349e1c42136d4506d9173d843258bdea44b577e1964510193203873710010adff53ac900d8c37a2828f9c3c6966e03ee16999f65ca7ee5c3d42871cf2005e3a1abfa315da5dc0e90773742daf41b5d5f217fd994d8545a6ab926554c50015e55e366b74c77cc0db7260def4b484ebc854841b65bfa4dc2e39e42988cf0080ee5d2aa21c6673ec03d97a61ccae49aea2c213bab7dcc6ad791e864901d600b676606c74a4b9db9a43e4d9e233b08134622459523ee1f1a3a535fa2db7a2008a356c77ff003bc60b9235341554d026936900e70a1f06c1bc16e578e6cd0d000114162f8b863a3c0a36af23f22d96bb58b494cc4d9f595a54f834d8984ff80036de40ad13e557b896e3ea4d4e00299fa09f8ffae365a51f08ac6ab7654474007f6400dc597c08e39e3a438e06ab4d3edf0ede4db79eb94187b2aa4b56f6840055332e860d32b488459757d4adcfb54325fbc77322b3bd78bd49ac5b2f07e300651a384266038f6619dc675720b089a7e850b67b7e6166e0740d47f98df32f00a3233a9eaf45f9a73557a61d98e70a6006bdfaa8de964a9d64d3aeb4e15872002f820b7068fc4322dab909a767932a037577da8bdbf399ebcfc14e947f3ad60062f47cabe9819f882ebd98f59a1d2a6ad588a77fe29b86627767f67fae1f2b00705949a833eb269d3749467ab16b62ca2d857b7b0df7037175a0c8914293da0056da8daabab34af43021f3a4f617522662192884d801657ce54c2ab4e7575c001d9d6479a5fb4f9c5eb5666b2ff4e70d8fe58a89c9b4dcb4643c0808c492b60010769209f61a4a485e7b578b29fdb00b2397c59ae66d2e785ade101d93843300af62d0dcf6b9e67eb82fee9422a801d74239a4a5a5f21a2c9faf17cf72d1fb00400df70c0e2c862fdc423b04a69067e29a37009ec435f54e98e57585d33b5800fe0dfad492bf320de3c04cb18393acc88246dd8020491b4d0803877ecfc6280075eb8902213c6a3134e49a795cd25ea2d2e347f1e85865aaffce2450eeb18e0078e850cd082f095354f3636a768b01a2bc0b3986a5da9b388db2d02fd90a5300838630f9d189e891e8b51f5586fb44ddfb2c5602d02461e784652e226f10e200b1c38f277cc62fa628e897b1480690a1f55fd88490adbec85e46e57b66977a0083093c0d22e611df004801ce59eb55fad8e3c3c9c44ea33a07346f77ca68cb009987e1fe9f6751dce2877cee17deea48a9109128996e4e2c51c015160bce5e009093ceee84772d60e1ef171a8e50d247f03c003140e267294d8a63f772219900a7bd565a8f1eab24a2145910c2e5836a7af7ac2728b14fa74f9f47dc7f2f60003a8e8b00d49990c92f60760c20ac3db98e424a2045474c2c623fbc7342b9a2009e33a662866411944e989d03f1046ead53ad4d2abcd51f6c2b9713ed9460b2004830dae5347f921a0c6cc44e5a0f575777fae66beeadb714582fad7b6e54600064536da4eee006100ff1a8172ae4ff9f4476159b29dc28e2986fe8c7596fd0003eb99ed678b4befdf1444385e855dd09ff436ac36e94b62f965df4537195a600d7402862e182c0d2c26663583c1a6789825a9e9114e7a4e63b1dd46a2f8db20092a472aae0793067ea3b94440d5a45b6b6270f50f41cfa5ed6e4487d13656000204410f477d8e48e229749c66969719b35adbfe2db2c93ef4d01eb22b113f300ec32b79b03c0870c6b13aaaefb825fb4d691b21e10ad013e3fedd31a9f37c500c3aa4c07e18d2b4a0b90a76b606197d5bca564965eb0afae24b0b363e9693f00f425e9011fae4b2f00f013f5866585062eebb29a0c6cb6d80bcbfcad840b250018c7936a2556c3192ee296e8beb4c665a835cb9faea8512e3edb4826ba6632005c6ca3f7d24fb576f80e75da7ae8f9ceacbdbe99c5fe1e2dc36379ee58bb8100d98147a1a3300cce0383a9231124fb117d7c8216e08938889b74acecce8ace0090ba9308264cabc8f6d3348258baa8e4186e3fd65fbf1657a8bf44b861ceb800416aa8c07150a8d8f735b5c8122bf6d27ccb3e8b96f33dd525f39b3254f2410099cc006fe3c51b2b85543789b73a8e806b544a58c25996708fce96c7526af800b4c257e8ce2f93967d10512b09e5e320056a8ab8a981dc1fde4685090a7312004dd30c94c20a46a7077ef4f148b4a103a09b9ddc17448cbe09d11eed175a11005d888533e6fef7f48b4a36de65a7cbc5f8f8de7f6a51d0830e46f02ac6d3910050055f29629a677b72516fe016b12a87f556cc35096e0aca9b42a1117d3384003edd08a0fa18e2aaf382d6204b86203060029ecef3806ab636fac718eb6b5800d8eef5dcec896d6fdba7ea8dc69ac2cbdddd35d957d3e57b1d560577bb0e9f00ca6851ff7a5f1a28b13e01e20f7d675370e73ddeb018d3da873d106c888d0800b661005f283223c9c4f5a0b57634294a1420852a64593531ca280988fb4c5a002820cf31b810c449d83e60aa0b090f14b143d63096aa28bae472c48ba3539b00b21a33385791127e22fcffe3af4ad7553ec0889b8cd3994087a7e07ff82e1b00778559b25bf37b762f0a3a8fa3f391b8303f18996d779d0c71a65105648ba200496e503a3f97f740b680dd4f1aedda721637e0c77a7c5ededb090ea57bb4c000d7c4c95a666f7e9958279c743c6613cc48ea887503807eebb5348ce34a81830030edf57c2de75cd6ba9f55911e8afbbaba0ba5dde979bcd37405b4cc23c3cb008dae233d0143d08515fe73b45d0eb9f73738041e02a9abcfd02e0750f988f800d3eeb93e6a55bd51a331a50fa383ae0c364fa5ea8edb1e3e9e5dbb1f688bfb00740345f892cde042645ce4f0b74ae0c758d21201a65bfc9b44ad69279e345f00cc5496876eb9a36298a7fa29ed013dbe2de6fd90721519b76d2cc026d5e9100092e05e4b3015b3afd43fd6fc6405971ceeb410e045e099dbd2e1125594b69d00e0b72f3c3cdaadf754a3629eb1688acbf75149bfb5f3a2c07c9b15ed4b00ac00a729e9926c32dbcc9d7a195b3b85ea29bcaaf5323a90c0ea079b9c75eac63b0088d2feefb799f6074cc1d94a44f19c9c6211c92a30861ffb585c2b424bb552009a9debe758430b03112c8a89a52b4beba7574907749d6438cc150cddf40819002acad4fc3897d2a741ab646a273b7fb20630f1880da73ee433206985c0529e00d95bfb98b0a962f8caa922a7bad9ff5eed55b772c4cc8b8bd4a5b02d37bd01002e4fb5ce82ef5f8814eacdaddd64cf93c3461dfd56ebb4cdb933b15697a3d800f0bb21471ab3fe94523e659a268f5ef3fdc514f75b44346471e1755f299b5a00d50efc74fa02e22b17ba23113dea1d216f30c3b435a7fe57de123966b538ac00fec268eb51fc540269a0c728da8498df8881837ed0388668cbdcf76464e4f400c78ab1e9afce2c73e4ade1f56b8aa4766f56cc06f969f77c74567382a6a60b00abd1f9c350bb9eec70c54a5c17e82ba74edbab7e69e45229d6781ddc5dcd080006a67ca403bbc4bd4af85f39e6566929f47448be9619c4f6c93d90d090a6b000af09053ad9fc613165df007a23d14e60fcbf1d49b3229c7b7aee5e19a9982d00830e10b7deb7a0ff1f6212379ecb64da916dcf8092afec4b1aa5489e5e0ed9005c3988e38b343a079688ade4f01a6e3709ebb5d54be35c77cb228361caadcc00f832239a11d6bd26c1f288c982607385d662680d3791a342a07bcbc79519b90010d76c450cbb8637a867e08616f3735941ea54db91fed2efc12ad2fef2eac200cef14ae515b273dc03cb54e946c6c0b4daebc1a7648f433bcafdaceaca674e0018dbbcf4eff8584976bd66d17095633a999c3227264a48f8311dd135b44125000b1766938e33090fdf74b6b7a2d1538ebba7b59c9a94d7600e94a81c3f0ade0003d7592d40459049a10bf3add523f497bbf45be4315ee6781f411addb7d7ce008dd327d75cb9c807b7cb2db5f65805211d6ae7cd6ce804d2e193f21b203fde005ff9b0c04d99331ad4011767dcb24d8fa4ccf5d6f9490a80eea960d304ce5b00b3ceeaa7e9e3dcb10f43b1466d5ba0d51497e58db80ce686440325e86aac78009dfa9439ff25a3b5db6df0a2512a1fb2361197047eac10ab109a7671deafa900b234a1a785ca6c594d9b4d72dba2ffa8209ac68cdfbfb817878a53353a84fd00023dd0f45dbcb1eeb00ed4b6d6d6b17dec6293a95b828dec7adc36bf2bc58f00531f5aa8637d4dd48891c26be6328564b168812c359e7e32d57f58cb1127670041002f83748e84d02f7e727db8d52e84e8169763df58ffd5cffab2b63ad32600d568c6e9a768576b11dc3c67b499d873c85eb3556d37672b71b4b73f644fe40093bd4c478fca662f8da97f24a665c61fe0a6df03d87f3112e5df41c92a12a70014bba62c7f149cf85a155d9d3622d9df6390955917f853e45587866550168a00c73c9a02c304ee202f43a9506b6022d962032da15d10c580422d90acee01c300014b01d2a9c1be000b514ec3714bfeb8538c780bae79078b492373a5a7df3a0069acde0902cb62d3df200124e02690005dc9a7c265131b745517885eae2bce00210d293a98d2ef78e28dae286de1c122bc5975b48f25121bfb2e4ddfe0af7500a23de22c8224fbfafd848c296b334d8ee1716aebfdf49010d26484ace0c8c300a98f398c52c5534e12fd848fd4766e092c05cd622f7e2c117a1d9a1dd26b23004505a74a9e10b4c5ed3ea446a72d38d0c056256a06c3b7b1bdaa6b6251114a00a522cb77223b1164248aa9aeb3025635110e235f295e6a07892a0670b0ac29005b3264b6b4b3c40134efc3029e0111ee5fd18bf57845a5fc56509fe1fc4af10091490bb411df0ac0a2a29f668837922186ae25333e19cd727f6e26ac2df55400fdb98c5c88ccb4087b80d5dcc549287a586c5377cdfbafb0af664704432ea300d547093a4ffd6734a975927ccc2112de10f726aac520648d329c518db962cc00e6c421aa98e9bda17426c3e0cf393e94453c24f116896e796ee12d1831e89e00afc13f389bbe973cd6afd89c0a273ce9cb1cd42451058238a0be901d8e5c6e00aa3078d2acd8f415805ec3e255f267b4497efa2c44666ce356c5ca92e0fd8b00a303d22695dfad4b317035e422ffc13417dadfaf705d223f6b5ab9db1e9a570012a33cd6034922919a610e74fe77987a54916b7636a88e9ae1c526fb311406007e39e8e80c4852d6ace887d8d50ab2c05294810099d9e226043b76a87d70030058eb5f0dc71cbe97a595cd421e8ab5b692d650cc326c3baffddae103cc079f004cd317b9f72194a32897e9432c9ec033bdc65941e80cc6e09e00a38385f98c003a7d50848123c3949ee2d5f40a46782e7ad7a75d13a1d4a5e27fe662a8d3ff0062e5081910a2d4cf072af0dfdf52fa0579a6bbc26fd28a0de8e47e1d9d4d2100331d863cf432ab4d6d36c0f600b3678da4e268b2de8fd1e32b3032fd6ad3ff007f67d3737aabca35cd7d2788875ef6629e93beb8a1b81c09cf9f577995bdc3002b87be403289547198ceb7fb8632333bc7fbb3d99b53ed12d60e61da0ace0d00b1e07baed8011647afcbe4e59dba43305f354c433f8532d23a9d09053a018700382a06949bf02c34cd8451b8e45d32cbd224f14247fc7c89f4478fe7ae9a17004dc04efb0240e59dbb2f0db7ec0d4f19b8007c0ca2b9bdb52a5eec80e6221900643c6d97fa1832517c010da8257ca8423edeb3ff5f56dd2106f0eff8abe889001911a726c036ca14ad16f100d0e72975fa90f9ac01aeb255da537d14fed9260007b7aaac1b198db09a6578fab814e4247f97b8cf7cb7421c8790de8f6a98df0086cb3f3e47892bfa67e5fb03b9f42ca0d211a264fb924a5ea7d88d5ac4da58006472661aefb1ba4b7ef6bb5e3924ae3463ce5aad4c16a7f9221ddf13ff476400cd3ff85f8c6cca0cc8ed415c38c6f439f59dc084bdb52eae8a6d32666e7c9700d9fd374d1e3fbf5e9648f92b4001bd8287e52c73e3d3d820a4e3838b33b6bb000263db7a24e69ddb215e658bd54f402c772764a5cf7215267a3074f5abc1ff0008aa8f87b5f70dd6744d8bbe62b9afb1aedd8251f5caba8e2b4e20bd1086c300c13c12c89e5ee6fc0e52dd54b7b91f87a57281804714259bdcecd1eb00d188006a252644618f851629c29a9d8fea99244bf45e0a8e39aebe0e39cd448e61e0000346e41f050d926e8391a13e5793b607ab9202945658c98592a2b34d3c85bb004c22df6c6d0c2aba08c92c402a60ee71188d9d0e15c7fccab97865c79da89b00299cab6c21a42cafa11132dd0dc1da658957d849282aa5535c829cc920ed0a001aa3b13de582fb7c0244c7b538a878b739929111ebfbfaec3ea6ffb8ab4d82003b5eb0f21f003b59fe87699e336ba3aa3a961156038e151c99633384ddc26d0070c11cebc7502ec6b5940ed18cf8114ae19f32b23baa953d6df7bc834ddab400a8620da25ff58afe72a5c2e4813bf157a6c468a474d82c3974b4a9d2791b9f006f5d670d9a92fcc8e9a6ac71abb5c317b8dd6ee976979fc8f81cb29bbcdc2d00bc17ee61c1ee7bec2ea44613c32d3f84beed43f0802f7315549024c1bef55b0003f504af94e78c9f6b77875c27882141077c29ad6664ef5fdaf38566687253005128c521961e3174c8c5c7769b4f3967e1c3001f90aba6f885ed7793c194bc00a948063262f89ad0f2661c84944319f975b22c90e0198dda4a5cd5c286cbe100dda59d1144a82f0aaaace6b95c41a99c5bafcb4bedf2b299b5dc65eaca422b008d348c9565a22ff02f407be70f633eed10817bfb7c9dd833ac8a13e7534f1600b01c42bd07a2e516107765e2b81492d0a624b5e878038fee611e0996a7f11b00bb13aac5741acbbf832c56c554a01a3abc91f1d0b026f8b7f083073625ee9d0026cec140c69ba9ba473ad8fa172c5961b4ade1ba1871533f66d1396d9e8f340011000b92417cf865e6d22b4668e2578572c02968cbac0364fcee4a9a8eb3e400ee813d2e165632a1883da00bb9d2846128555d9e80a3b15b92a58b26ab1d4900f51e8ce25e6e7e284fb184b2166d66c18242207bb7ec54dfeb383137b0ecb1006023bce024269e1663d78ad1f09c5bc2ab781392efff1b3f6cb8d9a114faf400734def1a7e33713864437274ff8de4e01b20f721d4adb9ef706c94d99ece7800a71b80ab0acc1e20928f88a267d17ee1a543ca6d231e430bec3d210d74a3f50075e26cc61ddff1ff5eeccd1f55c395ddd44e9a7b7f723f50a3fee307e0b2d80039c4cd1de61d3b0c389e84e6aa4aaa84df5893d2a8c3ef1588d348bc8e496f0090fbe415740dd433604fd1aa987b844f5aea42176e53fffe73550881515c0100211ae1a118bd36e23914649ed7fd328885f604f805dd40619d75c732a40adb00d21de700b461be7b39782dd191655036ac4689f4048a03a8720c4117c4abee00f54eef34f878ffe40ff2e6bb048a8b1346c927924e97f646ae171a37aa587e00b6020d1d885106608acfb58542a236027fc7f91a083492e4e5cb89c790a19800dd4a6d8ff1688ac8d902391ea2953adead661c992520bed5b183876733b48900aa2c6e0dbfb8584700336f3de683eab8c4640fa9d386bc89d96b001aad97c4003391190fe5e4439ffb67fd2a01e69c344921b39b9c0bb395a0d947773c3e240019e36bd7dfa94bcf0cca573e46a6c390ae0c8605254ce0cbdf1e166e4efcf00090f5fb154f4034e049ab6953f1193823b187325578176140ddff668b4c302a00e352e531bb312f5887b3b107c6f349da5257fb13e9756383eeae03c78521df00d29e098af9af5dc39712fae5083da74766c8a1c5033d6aac73c0a2b7c27d24005cb637e31db19061450f177c6be56cbff279d30922623f4ecbde7a4c5fbfc5004c90d0e404a11ca8d44b3dade714dc4b3403166f4edcb6f9ee62ffceca7365007e1651ab2a2d2e186226443c9356412c619a193c27f37ea15474631bc5682d00db049a18bbd520771ceb98198d042d9aa21e11ea40ffb20ad451f6b79a233f00bf3e3139e99d6904e140e4bb1ac2261941ec429708c19c74f0cd8f695b289e00b6f891d18863af842619386af8b4e7367789cbbfb2386a1a1b116edde009390042d1cba425925195f525f27521bebd33502629d6569e6ef25bbf600c5ca80800ed926e07ea38b328eb3bcad1a16bae7dca4e920278fe4a1d4c27acb95bdfd600d48aca6a325e9498f3961ab3cf153520af8df3d7125b384268cfc67ecc3d4100fdd3bd6bcae20af4e4b76bff0ee94a6bbdaaacea163422647e8424b0ac5ee9007b8138bc319b70dedb5c0109dd1eed5e0ebecacada38035adb835b5738981400816a75aafc26f8348a961df2a47e980de4319b6656032a54e05fedf4c873cb0025499383c1b301de62a7a2902c581423ee55d499021dfe0b0b6352746ba849004defe17f3d646d6820635f77a7412c6067a5d8f9dbe3b0c150abde19b8afe30019eb68b223f0c61a09b455a31340dcf8708e1ac252c60137e596e82a9faa1900225a1f1ebd777739bd1ff3012a2464ff0e0da53ac3713b7c856800380782a100c9f77e902b3fdfc77a157350b38170e61575b62eb932424fc709826b1fd0a000ea086e79a73e9c734e76ba10b171b26dc62e7fa814fa0223855ed520e155e50074fa1739c328d13be8e8f3c4c030b0d4b72aa014dcd9704c4ff1afd5b842fc00d750056e2ba757c2512c14a33a45ae7997c52fada88355ae4b67285e66205c0007d064764835cbffb5f13d2742bce3ee3cc4f22b9df759efec563c43de543600019e6365ae9e46a8860624831777fb8867eed94101a4296d90a30868fbb4cc00b1394c2a8a3fa84c32ac89013cbe13564f24923a2e4fde4fe26fa2366dcb9100e6cff03c26afd4351079e7e750a8fdc55dbd2b7fd286975db67232eaf8e4150025ea543796b92b7c4ec6f68ca34ca60d926eaaff51fed8e033d59e9adb703b000070ffffcc64b102e3e1f198be3be5070c246498aaa474908a8c013b55f830001064ab5aa865e899847c680bcc1096e06167430dda94e521909d80988b5ca300d331add584ca7f81b70ac555f9956bedec01508b36e04e5f59a27e8a74238b00be59e449dc455d881e26143a1368138d879be7bfcc90cadcadc85d4ec24c2e003ef7014202be335228673437df6bb6bb85fa4ebf7fd4a2f2f5e52ea3d509aa006a0117554316927c7901ac7258b42b947c2054d09dd05f21cf80d5e75036e100fc5a9293a2329b974aeed1765473cec80f7189b1d2b9ab0471e7f5bd0dc2f40086c7e8114946bfcd18c456a8e47ff510cdacc63c63f0267e4d6b7ce37122250046c7c27ebf051915f3f2e653b6b02fbd79abfed9d642dfb71c2e6c1dfe009700b37f9310eb605c7b6839dd1741d1fa09fd244e898a6305c5a77882924a35a700ab2319d811898e14daf6423c92614c79f6dc27a08ff4cae2f308d969a5b1260059dbf00987a2b60c802396ae4a7791c57d2f9e9b8c6431477a0bc8da56c6a0008ff292733f8b9cca01be08fd2a6bb8e144c9d60fa0a4464361570fd49a8b8200bbe7c3d5fbb3de66eff7508e0af2623809a7a06ff2aaec3ad6db2d97ed35d40027f262ebafdeed2dc82f896643fb31dfd60c4fcd093c4d9fe580d1af8fd8660082c089711d5b0e10e612f1ef841104fc450749d26f09a5658e02f64a6a137d00dcaa4305f3d5e953d39c32fda53061b49637d014c0e8dd86c280468660bca600a9c74bc3cd04fcc6222cfb878a5f6e4dc5b7c75d337a7612970d14ecc7fdb5005bcd317ef82bb1407c0f60a1a5151e40f239c9969453db3b5e9e30d884577a00ed49acda47d76759b849af2a2c6344177cc71614808ab38cadde35f8f803d30020688d421c04fdcd163e40161a3a41b76650e9360e297bb8460165feeb907f00ee44495621f118e5217c0125520f34e0cd20fa9355aca42a19860a974e741a009688eeb0e5ada477cc18ea883874c501cdf151b281bb8daf7f703d5246a20b00946e3b796f90782e66c72ab2b8eb2d093498a3817b1cba149a664ea28494db00bf13b41fe74cfa01850775300c749eff600311ad8f82be010ee560b388febc00879e381839eab6077bcec20c584accbfa8883f28de0af52f768d1d37f51fae00949865dbf2b636b60715081016afb410c5d4e981c542a79ae0e852877f2e63008062f5feb28d5bdeabe24f8839f57ef74ee91cea189e032727cd70beed81b100db3f6eb4d5eb2ac04be27b23a302cb9f4c1493cc43d5bac58a19dd5a45ab9d007ddbe10288c4a145c595c97334052614a99e71dfad113584e40e7ab4435a7a00838b341b4603541320a29452c877286cc06d1ffa73adc68064fe326dad0beb0051b8bde4253e19047a4187d34c8941420d4cd449fd599f7009a13cb4119f15004b4c2d1c3155438147a519241ab7d8ec089b13b8af95b94456667567a8626400cb135c271c79ecb6658945afa0e1bd9fee7feb0b02d7a95584304aa086add00098d72d480cd6e7476f394e083e0a4f05d865af66e27cefe56ad168f08fad2f007a05d1902cbf14a465e0c577f80995f4246dbf28acccd296b8ed7dd00a5f6700ce793d1f78e29bb9f2b990bf422cd48421f5185c5bb18f62a81621b0a17ebc006757a27cf4bc590dfd36b0c79a3b23b09570e2ea57162d01f5b7df9d2c34f300249b76b56d86e09b905329b90b53ff3a8dc2881e37b61782cf168498bf20f60044f2b716b36b1619100bc8c18bc272cce3408e7d4022f9b49ecf68086437ca00c4b2428d7936421cf3197f8a15ef0c746272c92b9ab6c5650a2e055ad557fa00f1952da86dfc4ed3f208f71ce85db777b4fcc8e6cc96f17c295d5903a7454700dbf3c7c22d19c079aa76aa5104e04c4f6e7dbd43b57f3f8cd96301179da27e0066fcdd610bab613b6eae1e2319f20f5202a100b3141d6f670faa423551b3d100866d5a621a3314e0fbeb91493606cf43d24b62e45ebc28b67d22c643c80c9a009ccc85f4c979c4bf210d9a66a6e6086155af3c0238ab37a1921a73a36c22540036b33bd636c26f05629c653a8a2359a785df6ee2b42ff996d778ccd5af344b00cd90c82f86a4330e8878628511f41d8619ba7dce82007ddd7987ff5b91354e00f1224424e2933310e12e558179c31e391741ebb55ed1c73ab859bd903d1ebe0032597c8d96e6c9367f1cdd023915cb55b369f0301c1b46d91f26945faba643003fdff742fc75d7409da27ebc1dd8b063ba6c319f5b5d247bd71f2432ca4a42005fa4ef89d9af93ab92748a96e64f739199cca7379f604ca2399728a7be6f8c00c0ec1cdd8483f5b0ef01d78b02927dd7c7132db0acb37775f217f2c5f3fb520001a6afd4e65d1e7ef93738a771cf1912d3c351d9c7ff4249ffef73ee5855ac009d523700586ce6f6f841fb1ce3abbcf9a3c8caac8f6a494c7a050f46c61ad7008ba5537623299fb3a5cc5c48e83fb725c377a282777a3801148559d6b3531a003ee7f0634ad2a91a9ac44d03198e98dbb77eb29277500d8f1fd1371dfaee5000ca8d9e971c6a98ccd88350962f698e8d5e5846515e334f332297768d17651900cd85c06b3bb32cb934f872cdf4c9e67f82d1f5814c8cde8c74169d9292e98300b0bef65683ae923eb29d390aa7369f257aca6e7bc41b430cb48f6a861e55580045350be6b422f148c3adf552c7cfad5216eb23497bbe75da9843d83abbd4b6004defd8845f1d42fda53e60734e4f8368bcc58a4e0b859ac0545b2754d14b6200b145181642ded950acb499d30314522a9dbe4e8f95795912397751c5bc138c000bc00569e5b3dcb27328f4eab4928c845e053d5bb7866c2bcbe7f38b7d3303004990c5a78215c5b20769d41890c14b04d8cf673fc19c620a675d16fc773b0e000a86b7083c893d7e9acac6ffca31884b633346dc9ae23c6d68d51de2c6f1b5000e38aaf622d1df8afa9f4a1f8f93461acf48ac0280ed8f761d09758e73d8ff007e07feceeb6fe0c0c25103f982166e531131ba640cb4d51c1a5442e0429731008a865abe4388f2082ae38a56cf23ffd00c7c6b7f8608d2e6e400ad7dff4edf0061038d5b67bfb04604e01e8fe7a4232cb19256d989edda1253cd7f2127a6350095b4562cbe5dc364dc51a4e8121f8ccb42821618cb9e94d777d71916412144007d9fedd6250a45cbc9d19e72e8124ad66375b4a17a3abab1ff67602910bfa0007c36e432657e7d1a6461fd2a0e319dd0f21f6704328e5ac846b278fc706083002d229f2292a74306e6ced3f7ecfef3bcdca97716a9535ff6aa5de10db8d79500482a1f76ff5f76ff464fc737e08822a102458ef55142b1381b4924c76f8f94002fdc9966cb657937bdf16fba840ac5d70121c98f17ac7d911627345ed8b0c9001cc9a5de77e4e37d1f616b628a480db7636d087dd3a91d84b03817aa75a8a400be52c62a1de3a67f1869697f83e1619c7870e3103edce06fcb5577eab88f3400e003821fe6c9870469b799b5fc3a7fb2770aae5bf801e64d4318982211393a00ccf09b476cb395a3e8b991c960c7720cf8fd8b25116672fcbacb75e30125d90038b022f552f917b632912451fa766c91e867c2e83e5232e050b645c99cee5600a07293ca4951929b643469f7611270a5ade8d39234491f3a73bb45f34dbaa900a294977c8f2fcb2ec6f5b8eb1c44d76291f8793180218730b665610f5d1165002b39675035faf7b05547109944390301b09f5e4852255ac1e4598141c583ef0083ffd343797fb86e475e77a579ce8aad835be5351e04d35746db572de3cbe8003bb7767e62815de4448c991a785c2ec3d0e6d50f33331f7722c004c903c0d700952f13bb777f1afb6ca12a0031d28989d27aa88adb36c5ce7f6c04227fec71001201d8ed370d1ec015a725be05747167b298528df46517ebbfa569acd43bd000c3b26f443c27043ae3bc4109fa22e1d4ff7fc205013f5938080e1dbc7bfa410041d92232174cc7327d3a48230d82df630420dec7a448ae8afcefa3f245bbf80077c488e4f094cdb0a18780c39fd431376d10efaec13e2cff0247a3b9c62a5a004130d945abddf3a00bf787e80c876f216c4f912ed12ee46e477a967e7212fa00dd3ab68a30983ebb066f777e9cf41510740841e88e7e3a5528a416bd18771700ce7e4891c0e63ad45582332d68fc67d675c8d5e3395e991cbd182b7758ffa80046a6fd0114879c281311d0d0e4847770e98b905ab5b1e1a69756d325ab137100bd807ed11bdd72af9fc4153d5b18dbdea8e4b8ed0f8b2a9bc3ade7512a364e00e2929595256e2ce1ea4f2e5bd871057a25902dbdebe5a73688bb8bd55cec9200f02be0af806d871f2259d71d5049a8f9368c491b3daebab92cd084c0d65bfc00ceed48fcb4a2e2593ca0cdcf3083b9a8ca40cbc6628aabd47149d37f2d919f0034162251d8b7420c3116fd85b5802550474fe57d027c3ce18224fd65c1ca670001b963aea16b644b963c56269a0879d7fbbfb399dc46c75adc12dedb2fa912007ae384916f5f3247489028897cd4f57138d6ed2c9944b036f7cc95d63fae7a00547ac84183127daf3b8d479bb3458077094558961707fcd381a2c7bbe54acc00228a7767e40acc0323f9ff3c534a562fdff89766795ec5fed3d8b0b6eacfc000d28cfaae8fa5066770e254e822e461846f04bd09e609dab927235cee4ab44d0022fcac99e53b8fc881c9e8ed7e41c377408d370fabb4c26f82de7c2608caf000fed4bca7e69fb404d2652c4b45329a7c7bab8da4c5e4c8028f04a53ce6775800cc084724c838311d2fa0972c57e0b419d44e4a3d1462dbbf369f4e1b5eaf95008404568ec258ae4d4886d39d55eecc3370944112a6e6fa7676d6d9b1040baa000085c62c829b191915b45c539d35249966e7c8b46538373e38ff7a860696d30025752b4559ce16604eaa2a95d5c33366c0b85abd294438f2c03f6bae2356be00a240ac325161381a218df25477918ff232514e5c057308f199792829de2398002fcc8e8122d3ebca2b64d9fb1e214f561bcd7e56f2fc16e91a8337dfc3360e00ab138c6a53bb30fa4a8e97c30f07a3b558a27a673a2b7741551d847b51c4030089d894cf1ea84b0a3948819578cbeae446cb93cab6e5b1ddf7a67d63dc5e9700bc618a510327af11d57a482fc69f526a3a4d1a47ddf21e2ce3b3c11225989d00164c9c4d2d59f52cfd5672f44ec77bb5d6a9f9b24018301cab853fc798e2a7004256f46df7524b4b67cf27dac450385d4e682e0ab3a80516c868cd94cf2d9f00a7bcf97df4c53b0e1edf9001173f37e6fb08b45d9104c8024b2d30b6cbdeda00673d7df6fb97b4bb02585eaab115f05756f6f0579a3144b9a398f1ac00613d0067d7fa1f53b87313949a5d435c25a39e88969eb84e8cbcfdfb88666d96657200faa30855951cb507cc513b4f67601f656ed579e18a95495b9d1afcb66ac412008fdc472724b09193499a8889bfb761b27c20097e1a0e1095028c3ea2c2151c0032d975a6056d16f702decd003152079a09696829583294aeaf02fa68d14de80007f4c0d590674d546c5f9bf7c66f25da1af0aea2b29477873eea66aecdaf0600c63b136a23ce939a37a269a4175c4e11f090b778c9b45e852e60a55b9e67df000e4aee7971a2b14d5955e923e4790f1cf8b28939a8426650e84e34484f1e07003bbebbbe6d4e6a1ab526cf5df16064571fd2b2129e8e81464fe488f1d2b468006ac5de9492b937d33bc92244b6564a07cfefd4d34342dc24af7e738f8d73f50068e9961a6b07c1272f8cfc398c8ad67825b74e2653feaf61c54f075a6b11ba006dad26c88fa1bfef1f81dd5d4c8484bd294617fdfc9e1ebd584be7b8ad15cd00e496a2f368ef848d5dddb6cf1441f143c253128ed713ff0cffd08afef83b36008cdaf76a46f05164a381a8c51bc6a7349418be07d15042d3158456f77fffe800c536fd1fdaf769a1de33e762a2b9255d1bb4f3a52398e700243dcb27dc5177002d5db19d398fcaf123930df11acf23e2b0061587e3924673b1b5d56b2097f10010bc3fcc2edc12637eafd6089cb7632d05bf6dc6f6a7e20fd58f191c1e57c10086612433efe376b5867c9fdfacd90c47cbadf94989594d8ed992d5f50b50880061bd0da51673efb49d3a2635ece624dd16004d094c1c547aeb3d3c6278dad9009649b184a9fa57498b7c79b8f9a55d58c3dc93084db28e678cb9a68e3d2ac80026b6a6db0669997d3684abe45cb48cdbd2c7e97bac2b87e9b37c65e171bac300179b7fbe103e1c3ed3cd1ded5e4418b206286362b3cfed8ea5201e1db9ab9400bb7ca397d08983024fccc1440a72dc1d5d09b0ac9607db42102826850ef61400bd38ec190bb3a9648c9ea72550f5db92892418b53783bff5bfd673243dc37000a7630d62fa02eca2c7e4309bc83738ed2db24e52d6846a0282902caa99a6fe00e1f0bb61e129a94af80e6b7528a4c6afe9940722a5523c510569a016f02a9b00b56112d15afd09cbac234ed66f7c9999b62906592f820cbd98265ee242729f00ea91a307e89d7580fd9f97ce6d8fa6243a029bc7da37e8cf95c4c8e373482300ae69a56a2aac9d80b0e4965f653d7749a2c61566e898b67058115c31990074005ead126e5b2ec730081d1c80f2a8b61bdeb8b24e8f49990d968313b9daed5c008c4dab36d75ea07c1907ff9feacdea64f98d6fb34d50f25b9adfebfb3d851a0006603d0476de1005e99922398206aeb32326b2b271ee679395fcf1d2144c0e00d4d87adfd918071cd75ef700993ec7b117a57345e664d943e1f1721ca26bff008b6580a163058248ba9b99c46ec319a13c3da3521f575707bb3b057b060c940044005de19a987e33dbed9830f57c12270125de4f3e3c4ad3b63313082d57a30073e51c5b966da26170ffea1188134f097e696be76c2dbbe0be47e77398ba1a00e083f98a1a49a7e3caf4b8a830e46ea674944756ced524b890530c1a45ec00006c640d3e8319d35c6a1cae555ff632c8115196455e086a92a6243c29af4f8200cdc40fcebcb28279eb5c32097de9f403ba30e081610af1283f2b3ed09b3c700000b5e3aeeb87989f9112d7718fb9bf854a2dd842b9225b7d77b368385b501900fa505de3df0e3258a3cc7aed957fedcdf279170c661f9c8d3f64738ee44d0200125a768750d75de216964205937ed4d02a053b1e8f7ee7d52425d6cc119de90030a3c181fcf8f89a668dc2ae3c54a018307aa1b9018df2127e1ef1c97a099100132b836df90988091b9ed111f30868ebdefe08485ab0eb6381ef0c6fef27f300b83cfb483a1f9be2cc04e334ad84a69b8c5acbb260e92ec4d06a9a81681dbf007fe075430e382cd1507e168ccf193c59732d96ea97cd0a5dec3f05e8fcf60e008a4272f7dcf5770a23be5e8b1b6e99a62781e3aa407ee1f938bbb84935d3cc0059e004144b6782df6033a7e7569d655e8b30190a8898406c05f50a3b08caac00f2689461e21eec7abd2b1d319fd2a56eda302002b100d829a61a32b18b916a0033b5738d7556d71523cc9063262dcc50fc82be43f4cf01f308f6c9dfdfc521002e08a9c12bd7d485956f55bc26e6fe30b0235fe94d5d0b981104dae168a976001ec3b9239d9f501f344365852544dd28972f7b513e818239eabe394e81374500e31868c7ffbc8b59c9be5514245bf16ae48d0b85c35661e4cdbad0652c6744002169480fb70a43f77d372d0f769fd13fbedaf1daf662d541bbfe1e2d340fa3007a6dbab35e2a97a33b006f0f854ad9ef46516ae492d2082bb7c46a055ab10b001f29293c9c84f059bb7120ca9a9f5a22cbe4771de3eb31f6ff778a18b62d9800118d8426954499a20aa16a15b370c22bf8f4b290aae2de5b0ce86881b8902100408f53cd4c17756162eda56836a147bd0078f5da4d9d765c94f7d4e6452d2b00bc011b8be1b9e813ef16676040383e30fa079909efb1af708189ca366fcf5c000a940f930e70a1d2c4cef4f2bdf37934393106dbcea5c3fc736b3cb035b2c400699ad40bbcb2d6a8cce103c7c2f404b4f2985ba966cf1a1b31f24e8d97132400fd9ec20165846c499cfd5c8ad947a190d2eb3ca1b589c3a307e588b2cfef4c00bceaa810ad87ba08a50d8218c3634243412de121c1e5a57ee59fd986e61a6900d5ff86604c342561f6585e9d1e3c3e621f02910c173e7d9008842d660c52d800f654c114ddad848af9a6195c1fe2726f33b9dedfd0b82564df48bca9a56cec008e214a76ec820db879727e61315af572253ae678e5ce8832e539050406461b00a2d2792d3afbf59eb82f8094066627694e787fc991013101f3d232f495e36a0035db05450bf368796838e58fcbbfb343244566f039e6ba294df632d2938f680011e660557f630f3be24ec794f81483110903787374d54393b6dc7a0d31214f00146bf53809f0459e4088f8b273dfba48dcd09b64241a38c321ef1f2106928a00fb2c08c42d00d942e22c465a237a41087774a090c2a792d48e907dc24263a400463f5c4c28b4e8d8c02f9a69c938679c6db8734123a1ed865760d8d0fadcbb001f44e2105a0eab08433ef6858ca78db94e938882efcebc6978fbb8c38cb1c200e953ce6b766608587b1e80c1f8bfa41c91cee9c4e0784c93c274cb1461223200f23ac04e9e16f07ce086e92fd1986532eb31957b9dfba0539b121a488506a7000ae0a8adba46e493289eb384dbd2a64cc6ef7348b649e292ac24c8094e572e009d485ac5bf2ef61f3fdab3a884d965930da48e96dfece4bdf658c6628db37300af31783637e938f172bea0ff32d75b22cedf35e15d56d44bf014a0995f5b1e0031b41b82e0874d9e75b7632ef9c9ceba1f2b2dcdc3640a6354402b4dd9cbdc007f47db89a9554d038c26bd8e1e840964d11b30f0d43d7b1ba0f5f16c5ed1f900fe2f0cd4006809115f1092eacd86afc6c8cdf5ddd8a5ff97d4d4f1b08b2481008804afbd5de6931604b0ed2ec2cf74360911d305220a40a843bfc925d3bd01000acec5cd78e8f1d78c08246e0ae12bf566eed2703fc878ebe2b7191a5336d3003dbdf829b036a309235f7a76ebe4ac9151350b2121352cc3a6e3ee26f2e34700c2d0facb9f88ca57e891d4de992026c0e77bc5596912f6779b4eb55b19969c006c4a033b9daf54e2dcfa0a3f36094bf1cbadc3d2e9967da0fcff3187875ae500cf9a548226072d5564c0b3694e7412b6cbd64ecff80b5c05763b022aac3999001041313fe36ac027f8f3256898f5cb82bc18cba9c4c2d778c5760d8bc6ca6000236edf970dd62ece5ae53afe53e9959089f8cdfd753047b2852475f6cd679100d95795c5915515a58631e6e280708c8f8084044da69d8518b45917a88f70bd0013ff042b4dab371760577427aa459fccf4fcfb96726765e9aa225bae50eacf00a327c08fc397030c602cbcaff600f8345398f6e874b1f3a00501817249ce28004e8273393247996c62d0999b598c63eee77e21977ae5e3f77cb501b2071b5100c721f16ef37b175100cd6f01526865d249549c950832c223550e67cd6a45e600b2bea195023b7b3cd2ba5fa8e47bae5365b2de11dd0a29f4ea0f572e73b2d7000c3ccb97ad0d59bbb4c5d3bb5797a23388b74673190b7362a2b1b921cb3dca00bf79af1ad2aab95b733ae9ab2907d8bb63c9c1a54b35fc69bc693bd96c949500e99adb3227b05db578210d31d0365db042305ed9aaab41cf5343eedeae358c0053d6d76723cd3312f5e9c9e4cdebc069b72817f3eb9412c3026d63d92cb8f800c26ee91baa31129cc6ac8d63e885f56b714ef0aeb125ae3a2a90b4f70d0398000241bb9e4e7235812d2f614ac9aed4851d28ab7177738708a7519e7fb6504000e8ad837402820afc8234c2d964e97439f8882e023a58e48dee937cc17befb3004850c093d00a090a5ff0873d964edcd2ebd2766c8457810e1807a21e77a56700a2412278d4b69a522d776c36cdef25634181e08610ce0369988f04dc56cbf100ab43d52852d3558ee0f803873321c60252ecf6ebf6b61d3330f37be36d7f980047a443a129e63bef534b332c54e02170718bcc167b379573095998878881a0005f1343b8605da832a66527ad6a404ee425fdcf9e9aab7af29b514a63d755ea009435b0a59469bae315e4c8dfcbca3bb9cd2f0b0cae53b4b157d3081f3e6d800065abf580233b1ca40d75ae87fc5885210cfbf4e7990a220ca973fa9e04b5950031762c237d22f6b3f4446b3e0c54c9e5d9803f418df15ebda7f467ad3abbed00a2e7886a989eea407dd14b2f175b3fc07536c982fa9234cac7efbace319d1d002d7329164fdb96de3aeb42aeacaa3b836ad7bcf4fb89b1a99ff62af74fe8af00363c802d056897f164fd7f07f304682b1feae32e8fa03624fa899c355b15e800bfde0d0f939c7ebbd58468e4bcc5284fb836c66e8c4eb9b963fc3fa6896d5900d30b14369b8f7bd80abb932770da892b2a6785039d78b092335fc786fdace700da5a5d40463b6100e75564aabf1739fbea735079790c16315094f1c66444a700cbdb50dd9dc0cca358055f0901b614c72d35630a5af82812487bf80d6ae0c40015199e93625c0a330501a6bae57250d0dbcb4959d111de34f006297bb05171002368e75bbb5170c148ae2b2a24a20922c494d93acf79cba3b9d55a6ef4abc700cb8e23721398c33124b0456f88f592c9c8860e3b30bcc608aa71f7ff25c91600d42dbb85d15966be9138178bce6990e28443bda2cc81226a167ecfe7095b3c009c765c11273d17ad473a32cd064f53fed1fef387f72efad3ea35241a28c88000007f5bdecc9db1fcddcd4fe40352ca9a73a520f6561442430f895f5c66cae90019e4eaac378a07dfa71326d740dad9b2ef0264cba9ad52592cdd5e8a1f2993005bf6c16d850f22b7b8409882bae38eb42d060045e70a78dcd3875b3f79184700cc2b82fe6f77a0f600dc63caddd1834792933799b744f73092af12f452da0f007378203ee21ae85e4929f0ba104d045652a6847f8e9d9e330389a5bdac432000976395e7a7bfaa5b37e926560f7c1917dfd4dc95ee92f0971595e6366c339000d63c415a4cce9413260a8bb9b9ec2d3d9b263d07fe2520977dfcc00c19897d0057cb6f9a70cce3378ffb3085de6baf7865c5a15fe1c58096a8ae6ebe3ff6620080f6752524b0e122c5898376ea9d35fe396f0c7514e90decff7c80cd6156d600d1bc0ff9f5b60ac6b4d1d9516de1fef899e76dd5dd04130b2b4f92b5ac84c4003afebc3023c34d3f83bbd28da873d8b917440d306b7ef70c3a3a3326347f660017bc3e2b54b000bf03a675e49038fa7c73df3418c05865bcf2712ff71c754600fa786c1027a896f34f52e684a580e84c32c4a7294616d0be82f02459bea9a500feac53f439c08ba70bd19a2036f8d30ce1b6c8539ed0a946ad4a7e00b2dee800ef1437d34ff9d6f673ac6547cdb0ff6868000c9db88d9cfadb9bf08a610fd200c3535753f4e386b08ca40c1ce45a267731398bfa3a45e82b3fc5af199d7af100a6ae53a5d5abd6ce544ceab8581a069760b75c078a17dbadd07751c7e52eba004b85bea2715a289372648aa18593ae981843b6808b5064acd280403a488baf00e17380bf5f84a31bcaccefc77c1bb582f4f2d84931ad90294595c9cdae294b007a3f79757fbb75ac0e906dab1b2969f7648f2699adf9593b1c93b28901b3c200348ab9a5dca5bf021c0b23246444f10ff429ef7eba21bea22f461e1e2ba43f009d158136a4c097910b92bddf0627b8264baf82b1bd60235299849384f7cff6009a0a60f4854c0d1a9b259ef0fbb04c49cd7fdf8f7adab7274c8c4549d76fe700c72edc26b9ea4a3aba10edf0ebeb20a3a89bde53d46852d5e579ab61ea519c009b12a4cf4edad45c6469bb4ce673b648835db25b6b41240e95f33b4fadcc6b0005e8899b5bd70239d70b196aa8e96339fc43cc2ae33855881a7a2ff71d0a13007a87d1f9dbc28e352267c11f715b5b587f336e74ce95e1cf1a5fb2e0177c7d00409039806811698a154be49a9b8e4bf50a40eba7f2cb52afaadd9e7aa2973200478b5a95efea4c7809835faf761485fbe002f6adaf1d8f5c9042cb133100ea0002582b231860a63e98699fc9230de20d681c3b749182a036f4be51eeb0a9f900b6bc7dbd86f41022b8673efed1b28a910535c163a3b1ac9db99d902813813000b45d6d98f53b921014118d9cd56f070c540a033d5a6eeb542893fa21aa6440009b2c36b89f6cd07f370dc5f86844866cebad695e2a8085302d95c52559aa2300dc438f8be1b171b8725534f4107b4aa35bd768820c77a8461c41ae2c070f6b007f181aef49d3cf843742cb8b4ac7a93247378a76175fc49685e6ae73f6216f004287c4f115409bfba6482de22b157e3353ae3df967afd9a00487fec758b2e600cae811a8348de5e03812d8ec26e1decf39be638e9ef139d87cc3fab388d0a900a8fbc23fc7d3568715acbf7e58a24c7843b9aa1994448226e2c49eece9a24f007846254953564af74ac314e791125e58d693fbb775051cc462d3645f8bb368004690d892fc2464e46a702bd01f2551ee01fdda5fb3609d8889fd897c0cee7c00337ab8a92fe1a4973854d64a02bc8809a3041291b6ccbd144a46b6a06bb36e00450fb8777b499ae7922d44c8aeda75ff1c51d0b644db6b84066fae38b579d5008122dd93dda2f15a1a9d9fe27fa0fd6548bea068096a7ff1b26f72af0dff1000da986e16737f589f7ffece4d192a7a547569c814340589111b0c8ada89e7ea00caa01a137b7db4f92a52738e2c2207f8d844dfb04d46e91d40b5a2cc6315f200c9c0ea7b591200f5cf127a521cb81c24f0b373a7ceb712c82a0c7ee3c440bf0052fd39dfcae8c6111127b7d12c0a0851f265d190bc972254611e59281a7df200f2d679f0cd2dcfd355aa10701f5122d837bacd4802673a3f886a842477d07a00701b5fc14eaebb0157ea68d8e4218a94afb6782a5871f914feaa0c76a8fce400dafe689e0585872c6ee46b077427cd41c455723ed097aee625a6ca6ef3d11200f5fc47a7f687583ebb082cc6e44f1d448cba58b945af35a895185e0f8c5547007be046ca9764658b48c60978ce136697d7ef85bce4596418f9bafa09488c62004a0779bd2d2ec596dd82fc98f016ff807e7da41124038bdeef1e28dfdfc68f003f0d766cda381c8f5bf8ca56f10a2c9e023d74c872ac5cc9a3891db660d23800d56d0f9d301f0f51fbd31d3e4e26bca9919abcb4b1b64d8bf57b1a38e744d200dab4d41aff80645e2711f3582808cda567486edc3967c85d405cc12c60b5fa0029223165825e34b6ccf16e6842c607baf25652215983a3480bb2d562b23f8d00b48b3bcffce03e83817f697f692a0c5aaf44a976b8513ed7583bd5fb17e92a00bab5d4fe6328fe69c087a6c885909c43d637e3a0888b86c40f380a84dfef5c005ab4d848239ea1a578d7c919929fb6a6808757889a1831f560448eaebc681100a0677fed523e0a8c468910fe5112bb0f50b46399484b72c0a2122859e240b300d1aebc17eebafac33ba1ab0d8825d17dd5b90ae948cf59184e60be45c43ea3002617bb2be66fd97a3b31a90b71ecde0ae40e4ceb6ca6c168c5190f5d70ae3e006efa93bce6d0de77b28df279a66d5fb4b5ff80550e26e73787f9e8776f7c4b0048828738053dfdfe9f199042a7d81e5e1508c9fb871cd3621b2f419d4cf2a50011ee01083a59232ae8be259f136d7dfcf3b24215f006e9f43aaf6e26b96cd80091d998e6a8498fdc23a7ba87850cc1cbab56a5380f080e88a825c25e459fdb004fcafae71c066a3aac7f43f8638911286a215f52c777b63c860cd7ae1f8e2400ee7070030461e8de409b94ae59345a22bd195089d0ce753b53bb14c5d5828900f4524706c4aa4e2f114eb730b3a3dfe8c800d316a234f95b21e09ff9849ad1008d2959fb7b3171c476c8e03c72addef4de636a8ee7f91e7f50e5a697e6cbe0005b343dc9885882a2e727516613547319742b76659032f78d99a171f02977ac000676fe8ba3def5e01209bd9fb6488eee3251f15865eb1ced75a34d2f00e8290097ad22a4eaadd1c0f612bed8b9662d1bf3dc0f512eff9e42f70b1a93cf3307002df57fa0448ec6427ff29a58f493fd9e8e3921af54de763de5c134ed97aa6500d6827f59829b6a47d2a4a297047ed3e3afeb17acdddcbc2b8a30f9cf8bfcb30049c083cc4d482c0c3aa6714bdcd9476d1466add59db149d393f44565fbd762000cfdf2c0275fc318e7cd727437cfd7778008ba86c996fdf872387568e6842d00f4dbca83701042902a696bec4ac99ce7f8b99c38b3df29f2e9e1f8a5003646001e75e79aaea8926c970b4c8dec0cdc19b7f34d23dc314bfbd7c0dcc4e88a2d005620b1e79caad9e08a5490abe6beb6ccc566be5fc5b8ca5bc32b88e10a8cac00ac880df8c4996cf3ee1cb82d3d035d4703a0ab6c83cf846eb8389d0a2465250017acf53cd70396e8ff17ce21fdc9f1f3987e4062e946b5fffa1cda30119cc7002a310b3edf6da39e0dd0d29ddc8aa841dbeb1cbaf7b7e6a00bb4bce0eda45500421b82db22d0e822ca5f80daf81d29c044a432756822ccc3b4153c46fe5b4b008b1404ac87edc6d77c328cc17bf11d67ee44c984b85359f5f79a218350a14500d7f901ac07e3fbd4db765e9b6beabe6f2ec9e0d3bfe619445b9f1d6d5bdb6300603cdf9e6266146f329a0459a1dab8663f6b2db76de66830e986948c21ed18003cee2b4b4061d116237fa30d9db1e19ada5facf8e147a2b6f95232bf3f3cf100b47c04b51ae962f53aec4d1ffa271ee70252fafe4ef6513838d17f508bffdd00cc0cf401fd5dd5c608fe873648c46ea5186a3baefe08cc4357e314888eecee00e9fb7f67c4b6ad39bbe03b6f409d53895adb0c9f0c016e3467ee2174e8a06f006e1aae5120400acdff78fdbe8d905064e6250d807a6e93bcf78d5fb07880dc0005d00a66be304c978ca1519807268ca71356512e2bb3a5103af31095afefa500459fbaaab4f1d05f813e1727c7adcb080273619a0cc114245f280476994dcc00f3bb541d6bcd8eae3de0598992143e698decc384d2883a8c23111bc4d5de32004d8800af45a4d28af6c0710b32b8600a095b3ac98c96d33ef5fd15ec730e9d00b474890f3f494be0244e42c0317d619fee8e98973f347cb584b19513cdf171001e001e9854cced02075a8967ac7250f0cb3fa30fb226595ffc36828cb67b340071d6580960fc12628e255d5625c0d118125d86a032c55551f8659a60afcaeb00654c3bf74c6896c6aad15535c0f5240274116575877461d7fbbc6438fcc64b000cd1a783e250f5ee420d396a5a8f3f3c3ad6a9bdaf5329b18aedc46c72ffa9005cd59f24f21484413302029248848bea32b600661e37e105ed74a7c949cce1007c775655aaf581ba63d2eb0ba82cf058c9fe990e215febe10f232c75d5dd5b000b869a4875d4671260163d920905164e35f3e942b4c2134b6a6e8accbe522500b5c33aa7a42e6317ae81a17422c11d957d6b439c7ca062070a4896df13aece005ed12eed30ec973cefa3f5eec35e25cb296cbc5bbdfde7671e2d586a80b78c00e3bf1ea8306a426015b1615f6e53fdcfac9feecf9b140af9e74c488d0c87f4003e08527d8329f7b6c09b276d1cf77e5eacc25484f0e2f80fb5c66429c427b9000e600cf984d593c77df2798b81cb89ea5a7a3f78dfb8f13e7257cf634bc96c003dd163f776f395e45cd7019b966a0cf56adaf16bf682360f616a16831c827c00009fe6ee49738a232fbdc2ef9235257b3d71894b36a152b738e3ba761647140097752ba9d597328dd3cf081d9f92cce63217647059a3c8feb179dd4a837d8f001a9d66fca8e9c8729a8b13ac77efae10a2d782ef5a9652fe5e8e5a1b99413000660cebe01cad6de785cc5aed0fbb1fe12763ef56842bb56d0ffb62c4a308c200ca64d1be2a7a8a4fbb5fe1bbbb42fa77e63894a49e9c91bb690670c75a2f0d0043f5dda246fb8c9793d79208a8f2c57e729c91b62b9ae17e59328e703a050d004924e0522d56590a3049c575dbfabb20ca97b9ec6c9fff4e7f7d8b837681fe001465023304656a177244a7a60ca754d2a783123d2d8661cb82301fad238bec00cbb90592f4606f9e55580be5d1ad6f6400647a921cee4c632bb483aef143fc00727cf1d6315cb105285071671307fb32d86268a0f9af94bb867566f26ec67d00d482ee79fe33616458fc76b4a964c30a02011034771ae075a1af2020fcbcbc007aeac179005749116dd23b487e048ce2d8f7bb2dda73b24a072b140635882200e98c8e9c9721a764cfecd862aee0ac1f01e06bde26b1bce13fbf35e523a52a000102f8d1a5779062bd630bd3e6334ad9ec1034b8b38bb7186a90ae45458e910051eac0123aaeadd54889a28a29bf8f277bce452237d33bc7b7c608804f022b00cbb4f803f5616efbab44963112a87bc81202515078278916b68b59ed54a72a00dc16cdd7c5d65282a90eede66e966a128276b4ec63299c640d7529f9ac554000900fb749a0595e01165713fe4345a79d250a204693e01d98a7f4b7fa0fcd0800dec6bd01940b7d084d8d42a9473b516cf1aa011c51ea694e54316db65b6f13003e5b8355ba62323708f04ca6793b954f29d686ec7163759ac6f0227ae2de8a00638cfe36f2c4c4b51bc87589e79fe80be5857ac54cb97aad492b960caa66e100ad1026eb68a5eca5b731b6c64cdf55a07608b6ca8ea1db9475f1c459cc317f0065f8179ee41263a3b721c4598c564df0320d2077810e74a21edb140c0b3cd400628b7fd2303ada23dde022c29b8c7b36223b6666490c563add93a95f26681d007f27e5d3b5e1e947dc54bc0762169a8c1ac9d5dec7b5bbd658d703618e97120018e9472a05a77542a5569fbbecceb4243cb81fba6c5fbb0d89339afb17d01f00067dbecbba96f1eb2354d5ecf4827ade14166f48b820fe0bf82a48d8d85b3f00c321cffe0241b779afba1cde935437beafd0978d80ffb4d91eec0b3c5511a900dedee4cb368a677855ab6e7bf9cb111eb4a78eeb69f26412ef2c594559985f00e7a7de4e8ff972f5240b2794c2c0b7f0b0817d91dd98f6a664bff2882ad53a000f3b53f41fb1e03185c1ee03e36aaffd4df26883fae1164c5d09768be704f000ddb606860d0aeeb3cd35a709ac4456f48f56e211e42b73bb970f4e80673bc10034c4600a33682ce2e9f420c686393dea87b0347763dc0fde3745059f87434100d1dc38799e1fd9d10343a06bf3cfc8f6b48c5c3377dae2fc404891d044825600ec447ed8ea5d00eb9594cc3157d56c5e7f2380146a952387d6ece86c72b674003eec400c4dced873820c9f73d419a3b279a6ae0a8b4e2474cca4541f059b4800e3495e90c8c87ef1568aeaae6a980e9b0143ea30fecd67d7691aa631e04479007c72b523dfdfa223b39293933ceeaa461d518a9c48d089897c52e01bbffcdf003d79f20b1d74789aaeac9deec2189f21b2417233b5bbfdb77513db1eb3d47200a5420effafdf2aa501f409da602186fa961d4c3d3c50070ebaa0110f212758009a5c1a563d7210dbd9fae9a9b736f9c9aeb402e310eb4e8bb3567eb75ed65b00deec4d6ddc9a99f1efbd75c3e8806b02a6d799c7dc1f5cbcc0661acd948e6400623ec8c5777cd0ad19de53c9ec83df9a8b3d6166cbc82221226c4bc72f5a720049d8de26f456805472b180b3a4baae70f566e29e245b3ba7ab471ee7e963e70023b2bdbc163237d3659a69f75d748f78a379cbfc7c76652ca1ad115eded2e100108de463768f1716367d7a7b57b6b48b632f85b1ace8751900e9107fc3432d00e4b5095f4216d19ac2ff3d17ed1e4a8ee18393110b322001c7229934c7f2fc00cbf0d89502707b33dd7a9367c440fa557b80abd711b449f556f03dc24727f900d116681ff3fb89902ee86cad7a180ed56857a52feeddb38617aa9f569d81880020837adcb1af02500cbd40824085a7ce423867eb1c71e9e74844a49be3d96c00d99d68aac9ca105d2ba67c035c72ae4aa2e38acf4e34224852834251bef04a0037ef4e785689ee6794a359e9330ae9e2936273af29ff1830031ddf7af31707001b8419fa85782bfcd069ec558678d63d2fdfc92322865230babda986bd0a34002e83657894488c28801ea6d6080b68b43a0f4b1924c65ba258e6653578eb53001796ecc71ec3319f05de1edc67ada4aac307735c61eb6a3cc9cedb17f16aa00043ebcf2b67c0cad58c483bca5deccef49cdac710eac958a53de5a6ab7deb5d00233532d6b8b0fd8432786f29ceddf44798a3a7cd309eed13ec0f114c4e475500b0aad69b3c2afebf31f59b873470c49570df21d84383ba797ee34f9f0d4e5c004790010fb7cf8cecaedb2c4d115e9aab4f243e835c6fd468b2a9da2f5fb8a2003d6d883edd349ff8077640c9aa92b4898c867fc462602f287e2e4f8e913d2f004bf4499ada2c4780c84095f4ea7fb7c83b58b547e7536ccfb5ff102ee212b1000ec756d330698865c67b64422be1ea054f3f1fb2993fb0c99acec6a460890000f278913519573ef1174d17c8553f5906ac254abf75ba28c9fa84f89e1c9f7b0083e5790ffaf35da604745e35886cb933f7863048b88809ace8430039877688006ca865105881d19ef60450add7d1f785896a5f113f9223f94bb3f2e9e910a200b43fe23609f6e7fcd00e9498c625a4358dc1335bb82c641e42e4c914f538cf009356d3940fb148cb6359945f544c3bc2f204ce969a81df7a26fa3b5b70b20f00f8b50f5bdac6ea4d6e71b0bf00fdb47770cde56dfdb8866daba0dc0a761156008ffbaa6457c000268fa0b1a259dd1ae85e3b3b9bc06570d31ca0ddd2c7a9540037fd0764be4f146b6f8e0ab8a003693c23c49313aa31155addb391cba7cdfa0094beb8127edafaa0b9e8e8f646e1b5334253d10c388b20415300f08bb775d200ee1743d6740f6a6e59b791420e0531d94f5580dc955df38afbe27e6a0952d9005233eef0bc51d61cf715a778adf00cfd425283708a73b9130245bb4579a5c3009c39c3d687930e33a751ff6bcdb6f9192f91b41239a8989117932abb5ed5d00071f183487302342a36620bce61740ba7e8e0cba0408c92b367e60adf611f95004e705266b39ecc58ce12ef8c6240120196ced08324340bdb1ea905d126a791006b149c07712821cbc92282d6778f5d122fef89e5dff1455ff4bb6f68c7b56400bea8b6bdf1f2cf4d2c67a7e3718d1900e5edaaec3bdb9c62afddfec6dde4e000ee3204f13bab6ed43536e411be997846a5a7aaece81d8392c0202e3faa0e8300c25732337ef1a4560c0b35f8da51c1cd7666b791f4796682b4224fd9525403007a665cad122f159f25f0c21c200120e11b070418dc7d5055a63dc32e3deb77002700c8f3e8fe258d137492dafe076184b71a9ea5932d3de28ae7b02e573ecf00b270e5641915bd7e9509012d25c650a17c8a26933a629342d9ad3b64ff13740050d5fe46890c8fddf9d2397a9eec63d409171d987cc3a3a4ef1399aa0be33c0038fc312dc921116d8a36ce12e42bd53cd57d3a98a9ae378aadfcd8dafe2b1800c12243faf2d7850cf7e61c305312530f49ed136e10c86387e895bee0a6b098006c3fda232cdeb710670ca07d6d1f2a55014dd2ed842159db488a7c8d883ec100838f1dddb72aa1f80aa50c2722201b1786ea457a5037c25f1ae1f9b8e59d9700faae579683523d0e769205bb2166f831eeaec68b70beaee32c4266a6dc2be7007bdb8bc0b5e66fd82234831e3f705e36ec32500d0c6931639240ef733b13120092dc08dff8b4cde50bcc7be95b15394896e9ef93a8b52553551871533c026600d65f948d2ee9ded659b732595b572c6d8c1c4879102b81e3ed31ac26019ffb001a97efe434549af355c7099c4442087d073c3ed0070fed03499f7814eadd1c00be3eb87e696296af6e146882434db758d6a90a9bac3d5b99506c5c4c017252001f99c7774d5bff058ebb267b950a4f740513bdbab398f0e5a08a416da28fc4004b4fa0cde1e86f3a9a28b53353f19c7ce99e9ae03b90b89b1f3caf09d3b6fb0016b3a31e89ba4d9af0117935b1d45b4d112fb0a6f672d65671b87a29520ab000a558727ace9880f4480593ec40d44838d45a42297ffc6e69095a2b9139faa400fc7e9acc68cf29638ea95e5c9352f4dca88fb303bc16da976df68258e86cb800bf5c2a59a0a6894c3a57c8c46ccb071dc9cbc4f0571fa48bbd342820b04e34004eb710f4991b7e2e08167e8a4160c9c169d8297fdd3dec10d65c94ffbbae10003dadc21f2750e7e26c4d2d7ae2c9693835581db9dbd4fce8aa5eb77e5ee56d006d8bb4db7e3534f8e1e39b285bc6af47f371877a59315870ffe5961b1e194c007c3b408563a595f3464cfa620bbe1eaa55a4046475ba16ef26ea3e4f3272a400a5ebb2cf75062e96d46c98f27a9bd8a55d00fd7abbeb79d0fe1b53b33709a700aa0781b018aeea7f7e0ae9bd814cfba0940be6b81d373c2e71816e733498c400e235d8c389708051a00a4ff7b8dfda7522bc29af58cda0b640d200f5724bbe0059194eaeee3be327c2993dfc25c74c4ebb14572129bde9607c8413ce61630100393f68a88fce375d6e5b69d8132f04f1a416ab7d00497ad9af35d43cd5073a00db4eda635cca9c84aa69ed4fbf742f73cc5d7a270eb09d712d8c5249bd615600ba55fc3bc1e522291ccd215cc079f862512e7cff84bdd2821552ac5f65c0f100f8752e41961e381c26194901eb5322c97767c19609bcbedf2c1970a8af8c1000973a4a928bcb3e9731b615136ee3d08b32b9e3d52477aab7e7cdd0b43ccd0a00a4aabf9d74ca29b7c20258e592fa977021f34d7a4c32c828851eb76b27b49c0009d9591e578af8fe4a6b86f943ebf6f0382a61cb158195497aaa731836f8420031c9b44a6ba7859a689791a24660ac5f99de573f24299596e6307326f2c9d100d8b5f6a0ee9f577ea2d72cfaae6f66996a31d3ee261d2c15a04bfc62d7a454002fcd52db50550655aaf0022bdbb031511c2b38a441dfb581d155ebfd720510006704aae3437518352be16e2f6a30c84cbc8f53320cd493553b52f341735e450037326bb2259265fd0dfbc01de422449c8588726e66b19604f39b463a87416b008e81c6e4321394f7f6c01b1a697af3c3f4ee499b945d8a10cf1fc476233f4900c86cadd0be72c16f9e5dac30ead1b00caf76ca585d4fdd754a6b3b1ba5405100b9e3c10edc825f309d4b414e6e590a5806be61afe3b58b492ffd0298ab9047006ffe07bbfacf98deb84720ab1cdfbba872802e8b6a03631849aa2675d452f600419a182b708199314bc5ef0475face5f3b6edf8f915a7052cad0adb77bf5ba00e8684ae7f1e75066403b08e5f81f64cdf293178fddbdba9f7f6419e8e351ca00b845f1e01e04bb1bbe7f7ca818a3df16704d375acb21b3900deafae0204231006fd08a6840350cfacdee2576fdcf31da35c9842f75c604e2f1a92ec4439db2001bf07d8f96675c274ad6a10bd4fd9a57a0b5251bbe3c981aef7ffd6e443cb9000165a441b713abe3416432fe03e17de1de8266966d2d361bfae1d2e91ee0ad00d421fbe3880d5accf182f8a9b45928c6d11bef74238ddac612bbe4c5d326680034912577d14bb0675e6ee024237ccf3cbe93cf18f1fee79592f1fedbce37ed00728d371f1ea4efd2d063d368d695e3b867dc0074bd638b2a14424b44acdb38003c2eb07bc9902f3e643ad76f7c374a757a92cadc5f094896aea3b4b65a979800ee09955b033774ec29dd9fd8fc0930d72011a39726c3a7efa33aa59b5fa531008252864c5709ccc7edabc2df37f1a5f7556a9a7405860fbc3c1c78045b879b002a6064d84eaf7ff88c9593a64d45999296e78003a784692777e5e8650c5fca00b7889d4ff4e38221a48bdc740d2f5728f5df53424577289db0b57860aa45bd00b6cb3c7c1087776b738a5dee1f9426bcff240b3131a6d5512ef09d8dc30031002558b4b2c62051dbf094703050947235d351a4cfe9838a914d0402033317dd00157b86bfbb220549db1597726257bbbe8a754be601d3ff2a1d48f1db516b4900c9e2196725dd53537f5abb98deba468c7c57ff79c27faff0101852f7c834b300440b7f42a083d7cf93d3ee3623b3df55a8f7bbeca1a434c39a331b93fac76b00c41dc2135d503999439c4aaf48700c1187378840c05ea339891903c0bdfa610021b1d1beaa3f7d3b73a2b75905c678635d53235d95e62185e58df657f28d54000a7da390d5994ce1496c4240d4dd5b0dfe517a631f24e4e45af0255021efbb009e13feaeb14a7f3ece4af9301df98ba7bf799b713fab0a3bea1e8caefadace004dae3f700eb57aa2df50b71637d27eec29e39d03814e00d5d8d3c0adf3d7640007850d66c2efd6e7e5eecd32277671909970561a81e1dd9d69ee983701d6ee006858782c61cebd145341bfb99abe6bc40c3b6f079c1c0991e98873887201960016d34531d265b0111e3c1afec802f16f7098b299d57e8339c283c8c1b09d3e0040fc51a616735f7c4367182695e23266ef509708f84fec6300e1adc796daa70019436e5bb64cf96f25814e7a742ab4690d01011a482d95f0d001ff3f8fb993003a29048363e93ca296c660e07c72a39bf4bf71775cb1197a774e76bca47d1500c07353afa52733d91fb86a6fddcd8cb9ed3d481a0bfa6d4172dba6b23b6d2900c11944379d728bef9d17bf1d16a622cdf0471e4ebfa273b0f7a10261066f0700f732e7d1b0a66b16ca449b6faba5f1d6729554a8035a6ee02f96ce2aa6183300c4b5758743a267b832aaec8752d67384354b42aff355b8908213879598bef40077c25c8a49eba5e19947df22cd307ffc151848d2e63638d84722b4c5628ffa00b2212f23a59dfd7d5c580a200168bc5618871c6705b3939226bbb8d01d96ff00a6f818928a16288b35315dbd9f8b615cb48a296294f5a3486e413b45f8c8810039f44c92f2e39fb1f309f87a065571db6082e5da132be45d7aa3ed739007de00f25fe72b8c5f5112625d54af111098110ca85a881e136742db614a069b2d5e003bb88e40d11593f28aade0108c61fccf18c85efa83caeaef6f2ded9e624e5300e3b704c6b6130fba83b1ee8c51154e196f0077c2f9f99c0a40204f36c1109f00ac64d4c1662394c9caa46d85626666f7873ef40f24567b849c49cc1e3385ce007fb9e31fc5a1d4bad03b7a5accb5ad73e1e877edb8c42cd159228512b3dad800771a3636c99d5fba13ce99d5408c37adbb77165d288628a16144a37c4d6e1f001cc277864b91384d43504c322bd9e286d21e4a808bacedc846c8d018344f38000a88db1e496e3b240c2af68945096fda7dfc3294d12c7a2954a92175227fe100ace6510974db1cb373b9dcab1bd63bf826e2c0ea6ba7c499fd6add6da6a9200000c206e8466c34a13851ce3fc8b3bc9bdfd58c574ab7e416b3b0731b2e4f640011f0d71070b8b495e8a54e32deefcb678fd190f34edd98109393e82017d4e400c5cde216015b032ed4cc6b6c1e748ddf89a0962f3ec8d6bfa312b9c2d62b46000206ba0624a363f07f1bbcd7d3b64508c930809c9de857e9f55fcc8d3d35de00ae61063472fb6aa0e2e52b97b932b2305d2608f90b07487aab53ec482cc1ab000aeb940dd6721200b7b528de60bf5539f4a8d59631a08e69f530b00f2656da006ac82322a1ed3f2d032219e61ebe949ae7e5a670de33d6b4dbb74e065fd8a800a36f5885d87840906947785494472812c52f4c7d788089b25395400948832100b85e94b971c4b207b7525746c3d649b8559584352ea3efbeb342d7af94a9b800c8350b768825d1d1933e491697a02a8fadba4043e124c0c26ed2b4c9f0d04700b0505dd6bc632f8de3cec161c111d4c78c89885f825f403f7c6e2d5afb36fb0072200dd5f4774d6aa66909958d76ad708c209c2e2501e522e0516616360f4100a9e719b7a8d6145259e6b8d181e177f17f1fd7c34759b1db760a924da6b20500a7d6ef5d49a13fb1444bcdb04107a9bc68194b8378a5d66ec8751c70d4f474009f745b5faffac80398990d10f03e62e90455c99161b23b82b88c98cf414d5e00d1759f1d3708ea02605e0902d416fe7c09de20a9d024a9f4c80149d670bf20000d219ce06ccf75ac3d88729c3354a8627dd720b1dea2fd6aeebda962c53abd0005cdd91a76f7cfbc53159d90326ff5933c9861ab82ea092f51823db7979f1300128b819eacf6d6de49de287ec64c50aa93f7b0509862cde5800f2349c0a37f00d772aec02d67141c9297d4d304e58524a5a5044067cb852a46377da655e0b80041e6a3ff83bf46c7cb95a22d6fbd303b63b8e5b2a23409d19bf86f3625209600e9195780568ac22dd7251ae6a974becb9cb60e80e70c947ba1f1b2c79c516000158955b0988baa45897b157f88d9caf8a3e931b90480a60a512ffb4a930a18003a323c600e0bab34677b628b669d371a1eda48366f6716f9e040852cb0dd5800443aa150bd8854b95366f9e472b94c079e3c2055f78f5580ba43b90f5c3e1c0048c9201bf077f268a30e6cdff7935ef5417ee72c92508431c72986ccc406a6005ce3981f44325841cc8835141d79cfc19efba7e27e9b43b0207a6b70bd15f7008601611badc5955085e940d3f67a5a5cc285b625bd68ff0866aacd277550be00bf297300c1f4cb2ed6ef49d51ce66403ae657c6cc15692242e8957fcc09c90006f479de53f3e810a10062452431060bea2f1d5bf304bbf59b3f0394a1f4a3400a28340d4c762b79feb79d0645a3882555e1caeb5642cdd71fc2e132e5f22240089fd62c6caedd0d43bcc819783ab4d8f5bddf6a482f03b82d01ed9e3db07cc0029d0669137ca70135ab5578d906a999c2a9ac38ad3e0ef9e424153c1fbb45f0026f89f029a3821ab799715bc34be33bdec47a8aed108a5f02a9ffdcfd8818600cf47b23ed3d067a2f8ab288b56f95965cef11c763d10e915341d194483f4380005b9c28cda31b85078c99e591d430da9d94a3635bc69e8bd6b4cfe49e9679500d5d59203b56ef591ff38deaa430cfa36145197b57e70fe8a3220188443df5b007ec2f06e5da73d008b2b43bc19dbca85cc31b49fc5c9f88815dcc7a8ba749f00d10d4fa0d150661e57407e39e2d814f4bc1b45f958f4476aaddcda481f64af00ec726ada5aea2622cbef1c61014246433c081be1ef3976ac31b6cf3b607f3f00e9bb1eeadefe95a900e4dc34be6bfe6c25c25dbeb69df3229996ac780ce099008aae53d3cfa05e46cba97c2e38141ff81c0860679e28ea001a8a15b27596d500236a968b4615fa6042b64b0dfaadc291b8325c65ca03742e061bf6c93dd99c00b4c9e859949c98b6cbb22bae8ee22c6f85905d565e4804b0139d427bba428f005da9ed0451f9f702d9bb4ba35608a9c546c85f7268941d44091aec3cb5b1a7003dd3d80e4a285991d419ce36145fa565ada47e08bd858b3540e62d12d598e90075ff37c873020682b66f081c92c039565bfff790ee7f4e79eae661a5a599ac007f5a4c0392b5fb1576e2355e7affdede6a77a76e0b280b0c0c1a297093f2d5008dac6c540a8d68ea0a25404402bc02028af652a143ed1b0eae2deef9cc7323005cd819670ad648b0c36f36794cd1aeea901f8ae9c868733a5c90af90776b1f00d542094d757ad3b20c8251441cecb864d49fdb50772e65a717b3d03b2fb51c002d8099b0886a26e77d35ba09dcaf4d32dc7433871581efc7ae8d2f3e1ec6520055ef769c226f6456fe9327745f098949b28c5e232294ee2bc033ef7b8f628100c382d599ea5072391875f99c929d3edf4c59aa0fd9d6073df3de541cb4f654007c15d16297d81b07ac3ec0b58b14498c4cb83f63feaaeaa3744581c88f5dfe00651c5ccc32fdd6abb0fab07d0c9f11583f60923b986ad5058d894c37c770c900e108298d3ea0ba5d995c9dabedfa3977be02705c499eb393dcf287f51cc8d500d9d758acd165308a9aec1a8c509f84d27bb8496a94db438864e1b9d1c6a6ab00d2de80dc01462e885278f04b8656afce0ba9d87cf7558c8356be2143ae8dcc00a0ee1673078b83b21d19c961334695ec17f57cb2b870b662f29af55176d92a004f4bee8324fc7a5a08ec63cd45bbab74a190461fecc47d9813cd0a0e2666ea0038a71419cffbd65dba6879e68811aeb2ec88fff92016f8081542d3b8050ae900fe41937bf9b42f14eee1edbd25dc123c73fa0e70362b3b28e6818322f791d1000efc16d9c6bbf72c812b51eee488b621496d3cd61c8d36dd659eb1f950ead300a00b89c3d60eaa178d7595a6aedd784f2d8d32ebd123f2bc3c4b2c384276f300026cb24975c44b9249596c2a9e8b0864990ed8c5f4ed5a8faf7275f5878774009347b66fd34130f8520901850a178e3058620958a410d6f789b297dc861f1800aad71aed6b5a2e915462123a83eec950b2176ace5d1d9f78306e799a3d9c6c0050a369ee230aad30bc1f6778b4bcbd7f263ec7ae526cf482451b6a8c7b3935005748edf89221041acc92955dd602eeba1e0e947c851d4af07271e86086fe9c00be8da12c772b9d85b44ada0170c1cff6ed2d5f3a8c44019e877abf7f3f9363000de45bc279349cca50b38f65aee06c57163fda50e5241dff5860811adc6b9000b386303bb1e3ee1a0a6ee1afed33f2da48594527a51ef85ef98db95f0bf23100b483bb38a4ff4e19d77fcded10d5da0414df13bf42f4a0e400f3c68d6aa44c006838d6b70da2056a0fa34f9844af031ead211f67b01089045c952ca8a28904001715dd5174b2a34234596024013ff319cddc77fc78bd1d318a956eae7db02a00f5a51109888475abeae2d0a71b61ab515d292e29563d35b9a8d7cc4b63e5a300318f96a794ecca51b17efc2207765a5654efe049b595d7539a0d497cf9a816006032677abad39bf0d58652a493e9af4b5fe2da97dbdc58a9ed3d35547addc500b5a720c523b3cd47b0b0c24ec0eafce79a44384d8cf066cff4eae7197e4c630005cfba09d9a3a60832d8d71c7fa1ffd2e2a0ffdb55c29399e09b357d1716c500646e77b2c8e051ae1a179501f5a0ea1d9125089dd1bd4c7e02a8fb4d3c0355003da451831aa40f7bff796f912bf95b766a66d9077e9b869ad1b87aa394ce4c00ae90c2ab20791dfd85d4c7ba973ca550bfbfd597127cb6a7915540809519b50027ba81262dc611a32db252bc4196781956c8443a53fa80027ce1c876abf75b00d8043559732d06470f4b8a7ad4135d82410ebc327dd8e92071b87b43447560007ff0819c7c9aefa84096ff593f21b83f894158ebf0fdf0bced4b20a248caee00ad93bd1c49c621cbd561022f346865e4e9ec56956a2ee7940df6cff8e5c8780038c5a700cfc9fda87132cb99bf85f4c580cac7744b3e4d523f651edd5fae64002cd1542dfdd15333a8e1af3d11d918f1ef6baec99b1c64fe3b583cdfe7e3c3008fb735e344c75999ab4ae8a669818c09df1cb858f83e2ca070645dc885636700f63a5227d32e7866a951f75798b4a634f25baf83be2d6056b040f95b7a815400e60539de2ed07802e24fa6f4654154fcafe3aade4e222bdcd0b3f76406cb5800b7e84c33253697cbf1d58a0979b3db8b82d686455c4a44fd6844a0b1f7453800393bd217e812911c1f3b52e619d23a4c8ab15997e275cbe0e3bff3c4a95c750076208501e2b11f9b0be1098138c21925c35ac4345b90c26614169b8f6a629200ebd883acfd5fd3c241da7cb4be1de3e86e2fdf70b4c4e7dd0e05c44b9edb93002f7c9d2cb232cd6240e47020f0e0b418873fb52c5521e33cb04a8e09bd6fe2003c8c38e3447019557b02f6ff9ead33d5844e29a73c91e98a6f8938a8cd13640078439dfb9d3fb0618999969f583ac2d5d160c5885b5a16fee536aa4657ff9100e10b7bdeb39bb1f8ee41c97b92369fa8efff1440d32e796f92781596be60dd00e00fcaebb9a421c345eac75093907776757432fcfa2c8dc3bd115d4491b8d000f257b23f58041d7d6fd64d616c55916805b9a7795c7ed0d28ddb609395dc2100b8826797b0ba5604cee59189f72bdcc4ba94490682f8ea11843dc32aacdf24008cd8d0b2eddd83def4774f0f09385ec91172dc1526f6e4f609f12ea42ff53e002dc08547c2b90e481639476e237e78e67545ccc896940c3274387d57dcab53007851ecbc24b067ded869415c24f6a5f18b73b3a99ece21bf9fbb476e50fce5003180bafa6e9ab72abf9af928da964fb7a4745274fd7d156ff88dfc479377e000d058cc585c9562e472fcaec5bd22a5e5105df9dc155a350d9156837c0ffd3f0083020073e7f5dff8dbcb23cdee9a41b74968d7af6d09863b7651ab65009b150029f676d92ff87a066969588d3c47f0f928922625855d706975dbff12fe30c90065e21bda89d23817c1306badbec392cc5312b87ddda0415b40cf266e43e1da009412c439f6ba476621665825432152ffdcbd6cfaedd9e4cf5cc627eba000a100d6e0dd0d850999fc1fdf146f38b076c6e90760b8b76a26252b297516208f09001350b7df330ea90864ab8402ef262cdf1d3bd7e48ff9cf5b342aade285959d005abeb23348b57814005fd555bcefc46e89846c5b5187b0660dfb54352ecada0012c1426d079a7af9e684cde23785d488239eebd3d1ddbec73ca0bde877326a00eb00748a39520110520af77961be4ee2cd9517ebaaaff371b22b36cbd82b130023c1015b2b70875f5101a71d0cd832d409264bd88a0f507c6645b89c4ea91a0011f2025f834c5a0623441b7b71bc3f34b056321b1cada53f60146db7a0865b00ac188de1a8e1d60f9617f8501a3dc2c55fea2417aa543f31d7afedc35e94320093b5d38c873b45cbe132877f1f2e0d6f3303faa9ac21b741ad5e6f140541ff008db37e3e19c09180bbfe627b9eab051c130029ba8be671351f2d7bd9b47f5a002f80222a61c7428fbdcedbc1c778e03b1acae1a8d229c79ae9f2a32dff525800f1c0d47ddbb6765202c346e9d3b0891ba2759083381892fe9c799c01afb585000a4ceeb11a3d20b380187b64eb9f9e7cb440ef4c0752ec7018c88fed1954f00060e6a71b86f89d755ae9eb2a6f99a3fab422a80b4abab3fdfcd322ba692f7d00330d6e47380c4199e73bacf47b80d76001b6331f055f110c12f38149c92f5c00fd03734cb4aa224b8ab7086af3b6d36bfe51b33e4d860209c2eb3717d9dada006eba9473d9e2d128d702120b206ab4068e2afb0caeba2ed5e443f87ab94eee00c30862ad5acff8d409e1ee84cc68f9f7d2ae761f512560302a3b99215a43d3008dc88f78df0c2ba12f4b4307d739d3796ef6d74c65b34a39c8808a54607738000cdfb2d6fb1756164ce0062e0fa46510a8060ef85284897876a008d70976cd006983a3bd39e765d1db499ae069b0b0a3cb639ee443c5567b01a1258726976a0036d15634ab925c4f48dfbca718cb929d04a508a8c38de42e4d7f51f1a0c6ba00c05d59aaa2a464c9dee25ba195473e2d0bf9b2c79b0613d4ce932074798c39001bd85c3b021974ac90cce937332829c2acdf50a51c1de0d8784330f0b9b0d70071a4168fbab09906201b40052902ef501d7053202b91999d9c3e6825ca6faa00f6e01dd15738701a06111594d6a8a8fd71d1bc193133243aa1aaedd5e7025500fe6147d44e8acce61cb3a602fcc33c9024ec3646936522093a2584fe153e3b00bbf9806719095a0aaf5a2c030d90fbf22a113c0b9604c0b8092c916a5c35a40036124855ea9880a14d9f4b0af0acdcad66284638d39436861455d001c79286005e719bdfe47bbec9d404c724552803294fb1947fb93b7222e686965591a807002942785f7fe3208f170e3298dc16b82de00b698222de3d673016326d80428300ccd1998090e37cbbf5139e7b6dae14696fd87cecc47bc44c2563d84b028bff002727642871e43f6d433b05abc81a145558dd425bb8f912da3af848092e006200d232575673e585d90733db4e0c31c6c9cb2ef9d8fe1e980014cb59e0dba98e0028f01ce9d6bd7dd29b9da1df9c9b483707730be1fbe532b2a553e77cefcebc00319ed59acba96538736965f512785a9d65843f1f6cfaead56105cf49732d3900c8ccc5b9b044d02a6c7f7abd1edf4335a75a032ef9fd2ce8bff0e653c2fcdb007ff56d0fcbbebb13602253b6f2751938ba706c89f75e2666b1ada2aba6e731006cc67b1a587953f6c1c5eb448c65153025503b59713683fb63a330055265e7006c9c6c4bd81db9414e06d8f01f9a54eb524baa33d3b357685f119d0b9e5de8002517a2cad86ee8651729999c28d85da56b0a2cd320c42892d53bdbdeb277bf0034f091db46db2a78bf238b0bf0e11efeeff89be2cd81a6fa990f955e99351e00b96b58797bed1ee3bee37721d482cbb6024c69e1ead9ca4864447cc4eb6e02001a317ad5b7b53d181108be3500f09ac214f4a739e1adb315d311d2d065130e00e199b98b03a38aaf9c0dfca981d323a92e2a7763ad964d24317927d8f5408200a72855dcc0835dfff7c8a8ecc3c04e65ada0c103e0c66d7255b19c14fff2140041f36f54190fa20e14e8f28f836271c4c2e48585f46f80c41c8df6f9793c4f00351e28a44284053e678a23428fca61d9f3c1bc79dfcab82c269aea5028555700926ce6e407f3d0cf612348dc3e8a8514896ad14ca7b8426a92500cce77c7a40090f9a11770fb90584e2b0ca0cae5692c5ab3b0354525776133664c3e67bea6008046817e4bfda8ec6ad2dc87ad6d410c7cfe7296fed3fd3962e035924301cd0019c678653086ce470601abff531019122efa858b22187235353482570d12970060824678fd229b72c33098a7990b5c81e5d87666e5edd6185887123e4574b600ceda205fd5045bbec8b739112cbe1fe6e39845506fcb0d15e1c0d3d78be72300b03dc5515fcbc87c5d7f9bf4a2a8d6f7dd3f782d7ccc0054676337954120ce00bd06c527a189aa3317fe5671fcdade393033d94ff797be71ab5f8c9b82192900d0fd9ec2263c8b4b6345a4c18724f6fb2d8dab9f7131e960db2ba509bcb01500bbe077f38313d8f020e8321fbd5777c8730faf8185e8cfd05865742a8166d500a74703b6cf023a4c077b38b818716025656d1b3281e05e6685f8e58d2a0a2a003f81ce2ba7bbbb422d5c5f5b3d2fbfa2f0a4ff66dadfc67db6c0f77eaadccf00ddbf75777efef2aea04ffd64266b6ee0aead86070114d10b3b166209dc333d004c24be1869c166a6e79b5f2d63a1a3efd381cedc11f5b2e3686639044e4376000b10f557fce9521a5a2a85aca72349c3c07b745e19a2f8d31c505fcbede382008255d30a625a1e83cdda08376008832da615ec2f6ce6391aea6cfd4669e86c008798ce08dd7bd12b3d13c14a12de6d7df9a353ebb406c04f0ad8b6a37ff5cf00e2b88d405b1e1024ffb53256a8566377b92753114aa64641e4a3f7cb1454ca001202910c7ca1b286284f6d934e93b077ddf11f4ce0fdefa7cf9a24a19bd5db000de66bcb448781b98de86cae2f2b0a81be3ae607bbee410f8ec9a3513aa20f00a59007f6ef2f2a04bdca9219ffc326ab0a575d236873b3ccf8ed24543376ab0093da94e7b39232cb0e9ff74026b4beacf29370e98d41df395070bcafb3a63f00da56f1ec1044a97e8c2f2b02b4847d36f79c1e4c5c020d1f24c3b7c04a5205000e7bf5823d6994f9badc230ee73d8e78327f651bd6c4e7a7846405dda6c1e0002ad755674f3987880efe6f9962e74d02841f845fad1866283eeff58be9467600e93e3012165f1a4bb69a9f8d378b22db98d0ad430a820c6810a1d578add6e400fcee631b2fe1a38353de9dbda03f8d77f592b60d1bd6bf8eaf1e713a7e38a60041811267fd17c9d6b5a43d9c1e0d9368953bbfdae39e0e6a5d785a5fa2e82700df22cbc733af9edf4e65ba8626976a39b0a2cb7e66ff8817a06c74b435cbbd005db63a502104bfdd239d53b2e7237ab08108c94e3887951f8fe043ab0479c1008aa1cd46f939b69479c31a03a0404adf7ec5c9abf7be4d7874b85e719c27ad00671f1c95442d79d745b9a5b1d3c3a2d2f328eda2c52d738ebc54b211fa5ed500c0f10a1c6fd45497f368eec981126c648322f15a44ecc7de5bc089d98a5b6d00af01bc3fbfe57bf78657a459fc90d01a3165d6529d7ceaeec13bb9f94ffd44002d4b61f3903ad3ae3a9736b012ea906196a44e165dfa543501800976ed4b8e001defd6737a47e682eb4afcc28aa064ce8440ce7ad4fe0f0f3f5441fdb91595002be3ae7c854fa2adfc4790ad389a1f72653ac4a8bdbdcfb0bacdf4cfa008ed00331e6d8f6871a32ccb8ada7cef0cfffe8794957426de7f969abe4b1319937900828a93f571dbea9bc7eb9d891ec856d0fe138f1300ff3db6a9a7ccd4fcc2a400f73f6ef1b2579a71402b082fda7399e3fe93aa2bfbd83f1e74173a17e2bfd7001c5a196e476e10afceb5ce46e05f9341e89054a6e9aa55345473b9286da41c00da479d6989dd0e70aa2a4b9aa8d32f1286d1d378f94ff26c6d634b6a5ac77f00082c7d6d88ce8e2bcb4c5c96e97896cc05b2026ae2effc44edbfaded0b981e002f78745c0f6ef10d2ca59867d64683f7ffea9c937bd1b10a3cb7482c360bad008bf29aceac280530e82dab4ce947e41021601874121aa0e47140405eeb4e46005c57956ab1474f44bffd85a4d64f2e71bc4ae2063dde5d47f4ccba5be80e880005ccdbdd7e8f9d988c5728f2a2592866ac2410be8b934a0f77dad03edf11ab006fec00b8b43528e40eb3e4d5285d255ea3c5ac9c1496ad378b751ee7a278880019c6e0da3e53977fe03b50b0d7b3ff4ef1a2271ccff68f628cc3bfc0fdc4c00063325ecb022b0edd73df29dd8e100f4acb9ae67223efaaa4f1a3f4b9bc318f0036ba22f6b3feb41d5430335c24cf27a9ef4c5eef450f604cfad9fb9c2f504100fb2bd282165c71e9d70f05ca1eb6435a0c2c906e825416d2c5a3514ecdddbe008927612907132489894924f4e597f9d8e89dd96773624eec8ca1e1e9a445e900be6f066c7895415375848e69ae4ddd2ac39bc852ba4f7ee097352e5224df8b00f85a0e11b7af7986a415fedbde2b901826f67eab7f8c8ea951c8138c9446590029b3f5565efeb135934da554cfdfbb508552f1b1806aac262f6217a601041e0041199a6877ce2c31f237870dd1cda014bd0c838fc912c0b381b04a7ba60ba500f8d944373501892a3888cbfcde4b6dac2ea68b943d951bf8c0c7536b40e4a7006305691aa80a27f90889624cc0c5069091c1a203bc38f9ac5806135bdcdd6500b50665e5822fa7e0e37b21ff93ba9beab925ba4cca826fcb8b850743d376920042b1cd6cddda206ffc47fa94c8e3c217860fcdc4edd3db4f8b4b4daa4957fe004e5b1d6cb9fd3c8847a98bfe38f182c787a7bfe64551d80b8c9e2012efe05b0023c22ccc02d6361ce6ca2d9658d9a7299c566ed24515ddc51f4d3d5335f9e200150dcbb75b1fb42d5b2f56913dc3313b1aaa1e42b248f794e1949a1d612e520061e9dd3450fb1a164eceefc268ec4e2d51baae25144df843f6e3d4f6f3ae5b00c09673b63f6ad7bef6ff5ffdeee77b0fe99e7e997d43da7d52cc8566354e22009562b2789c7837d4a74a26110391009c8f944a1b98021582401e22d71b8e240032135a43b3d4da57cd4459a5882d4500cd065674ba0c888b0361b0c44fde160032ed5058766d9618eae86be79721d770f07704cdb1a3200e37ddc68d86565a00e971b48dae67b2aa45e01076f9d0fdab33bea54b88a07a02f74418c62d266000059a424b251e93e2f96e67806fe5854beeb186cea19b204f10d2ca72b61dc7000fb94aab739310e050d08d13ecf8d938e70e3e7fb8bf7976e91faf3d1c142500fb1feab1003375a2cbe362136956459c304e201c81a63628d5bdbd3d4c0c0000492e5741eabb3f9b2806c6025e9a9fe06551b7d0f59c13ef16ef06356d341000e7defa80bfc80c014bf58bf0e44d22c3fef1e808bac39619caee8d675020ec00a42985cf739ced161c3651fa67483d533514794a3953e4cf7a2f273ac3b95b00980155adaf0b3d08ac749c2981dacadc8d1b899da116c2ea4f85fde359786800db685f59dae0481b398e2db640283da6188b2bd284c8c07100e7ed9f07f74300544b0940a418e2b4008c4e6dd9ca1681f7a02f4624f6a6751dbb94ef1274f70035c36ff437c7bc2bec862b63e992b579b2fd5e9ca40d054ea9eb93adc222f000c57ccb7478da83ea95b32a05cfd8b88f5342059a913b151c0c3ed9cc8b671b00231c6ea8f2a16418586d7ce86d1599b4789d50d56199d73c3567ce99471513004c44197a73f79381b4a778e36a37fa98f9c194007d1f4a1d539fc0491f0d3e00218fa9e8b1e432135806a53a4576d5053a861b6046ae8e8b97cbc92738ff9b009877b3f169745f047223b29e6deac912ad0fc776c71cb1101f01c20cb80bd000d3150bd8809ab2572dfa4d3b04cd90b3c2f4e0cc69c778f5df979c6cd802300081220f94d1d620ff5d76ba133f2c5df9318d85a28e00b6915574aa83a7ec8400ff539cc97af140635200700c931cf38c9417e59b80977365eed4065f238952000796b647eb7ddbe687bbf8d1edb04fe3d5c1acd50c2ad3088f09b450bb529800e3655474739718722e34b5edf1a3eccae41d62559201a60fadabdad486cc04000dc99ae8541bc0846f5de8e1132c326d071cdaf5591e66b3908902dfa0eae400bb54015b36529ba39db5f81e52008fb238c3ecb5158f34a819d1670ff68555006480b044c88c731c7a76b46e1346b72f855b21f8327d194c42a4bc1ad7a39900a937957dd3dbb00bc1c8ce618a9f65abae05fdeb8816f2721ebf069b99dc8600051669038e127372264f7e1d14e38c44b46a482750e6ebfe049ed6c6633684006dd92493f3becf0c08f1dc6d0503567d0fd85b6d12bab86af720a2872c05cf00bd34016c0901cf4457189e47fa24703eb75063903fa1034e99547e53eb32520011635b68526a30ada2ef32561506d1c17ad58fcdfcda04c6d6d92135e7a0f50004946d91086df06cc834fecc5334357ef88ecdc33c33aa51a99afab3dfc99a00261e2262ff99bebef81f5966fae1a61f2f263da4cad4139b96936eb6805ed1009637fc5f523977e5186b4b5011a1dd9a0fca3f904543585839def6ddf2a589009c9f4000458f3c38e4e5de1f25edecbbf16395e134622a6633291b70539e3500f8facc1947e8c791fc12fe7b512660678e9610191bab9ac28fbe7b03ae46ac009c6e8b2b6e97614beaec7fa2edb631fd54b7c1008e13ddd35d75928b1f316a001dab12aeebe310e439d735de83e3695f49f4619e7cb63bec74491a80606aa000291b4d572e60e15cdb4a6d9a9276cd55424366fea4f74e431b8807bcc3e08300babdd2ebfa51e2315d59c59a3dd27501f7879c030ac94bc1c78499ae65082f00da3d14e624b78ec6229630084092722d0caf3eb46eced7fb5b06564cebd372000b2d5c8d7ffc98b9788f9f15f126216efa2fd8b89b7c83209cef63dc304d2c00a3de8c49fa2a8970a3ba29fe2466c8fc27fcc4120e01116057b541f23054fa00163fce8b4d2a574968858b3a325535106a4ee4ad18b6b9e9d1834c820400a10026dccc20ea2cd209d0021d245999eaf7bf29dad6bba44a2b2fcc1d2b6099610068fb2bc9a07090602e86e40a1b974354f6719d5630596e58fba44121b6cd2e00535c907d01f5c3693004c3434dc2b1cfc36e4d6888ae36d1378fe2262d9aae00d51c59d37ce8680fd9c054bf90455ef9777ef6da8272c1249548ea858ad49c00a269b911a5bbb5e2ceb547468c8e3414f3398dfaf097f51dca9c1ea2149e78007f4b47382555b1298b634c7e6cbb29fa0d4a0f1921be8f87a6c4fcce3b089e00485e6c8eaf679fc2d66bfc17e6fdabe5b98e819b0ffc2ca04870c7630ba65000de8747a58109d94f144b7dddda736d8f43b92007b9b23c4c4de3d22045ba7b00e09fc6669be1a7f20939f466ef0bbb4a2a4ba9228640c58072765f15fef2e4000d9799534ff72ab57d654d0561e81fb39fed6d68ce547d5cfbe629e229451900bdb61752402eb87694b0f4d434e802bcb148be0960bff4a5c9a0568e6d6bee00518090d9685b54307e31b03d46ea76e2a271129768d827df6ecc719822a5750013d07b293cea07ff7dd85451900b06f9ef75dbf2ca37b1609dd705b6e17cf30022453df34934509a94dab058aaea60f37ad73006cd8abea6705156ce711b5800f220f712d42da63daa442f2faeb3ed75d03300db15d5500da04bb0f40114fd00ea670974191f0427765fa2b39d24eba7e25aa6b5a4eb9760a6f84d016f0492001be2b9b6291948d09ab8adebf3524aef6cabb464d45b12750daf70c1e9aa7300e38c004dcce0d91b3c55e8040f093c16dc071b65a32b474eb811423370290300cd69ad3049d20076911eef02cdf29b4aa8cc506f22c5cc1d7a758307e6d7d10093bea3a4c60d415193b30e89321312c62ab63c5f4d958e9bc282ae98ff6fb000ce7fa5a0eddda6d8d18d2509bcf9bdc1963f9bede524d59cd6376620f9f56b00521b5e2efd1b43c151ec90183c3ab2fbc3e225bee715552b6faa6033f70bcb00fb6308d38785faf2a80f6ace0855d261ae0cb360bc5939efbb305ffdd2c62d00275709a514ea4125ca81e28aaf85ea592b86a8f0784aeed366e8f0a299acf500d7b24388b2f063e21d7b04cf226a59488b1213f34d2ab05399fc1c05e3589d00302496a43dc2ae93d095e659fa743e17600bd6dae5aa1b4cd4c52f44fdc3f600aeba2fd52e8dc8ea720fd0362605ab8423540efdc04a98c3cef02bca760bf600d0b57aa1e5199acdde3c39fd6749729a59a453df6750c4ba89508e36faaa33000cf54937ecb441f34ef7dd1efb2e8412009a5258027732cec32529af91079d00c82b92260e70cbf4038b3d57181accdc802e2b1de0089bcf5bd7a8ea982dc800bfa5c18defc45e19c4bc1777bb75ba79f25d32463d74cc4a4cb22bb09b3ddc00eb59a4c7f1521e6e7282f828772053041d7522df21fb42795a041169b33b2000c610e7ad1cd21c47308cb83a5da99e7fcf175025851aae3c02bc7feccce0ae00a49625014b738dcffceed7ef52ec85ed2aa408823340095c2dc35bfc3c22e0003599e6ca421eedcbaa04cdb1ed0ab49dc1ede38fa58d19d92a8175aec74a5200253ac705e65ebd7344c434fd839530dd3395eb1a26efcafc721bfdc2565dd900b014bb6df3d0927661309a78985d1f3c8271ff3ddf78392a269c83ccab68fd00e0cb790fd742f94891d78120600dbc77ec290a80795a5324d8a70d165dd19900c5e5f81c9dcda763bc89df9a364db36538f61dcfd9edffc72239c286ecfaf50099a888aac10aa34bad4f26439bdffee1223d6e8de534cde399a07b77235982003302c232653fabef245fa839ebc66303e7dcbff605d51375b8d6bf87ef0ff4009637d0d541e96eda98fed92bc67114fc5f21151c194662a31e44a07cd1c355009713aceedf474028fe799cd3aa98635264d66328ee0cd041819d4cc2c98bee00a187c430f96a6ab5bb47770b7959438d513cafb1db32806b45f463e4eb317900988692a371fec2e3cee04f4a4642b5591b293f7447cf466968acc71669b76200e2a5f44077e77594a7f1f1f68353f1898321771894080b05b80c9eff8d0ca200ff29a2208b4d1811acd515bf4ee9c829970d6a227124eb5dc48dca7c6ad02a000774ad5f5b01007327cc1ff8b3b959ba298a09136a881a697da34ea08daaf500f6fc6e6056b749f94e2bb61ecaebcad6cf6aea2db2cebed20f45b310ab8cea0014db6cb2604d3571569afc5616b58ca04d55706ef368ef0ad608c84ebe8b0400839d4f0cdc5b5828f41237c5c24a6c045b81a7f1805c8c3c5b6830ba3d82c400579e70bfddb7fac58817d53c0bf02f42844ea7ceceed5155455ccbfbced11d00b22fa202fdd2c3f9641f704e305dc93675f6f1426805a6da21b3c33667e6a800a0259f4ae6507fb83316e1c23ed4781af82872d63d8c6771eec0887522261c001cf6587c86804de5002b950dd850d0738ad3240b56f4881a5de85937d6f28400b7b96a9ffe28e52e94ac654b0a85c3fc45f04a85b9c106f8a59525a8b8faec00424fd508233c917dae99d9377f96d82b75b7c5775355f1ace8a92a062641c4003984f8b4b8e3286edf1cd9c844807b808a9d3cac327931a9fc2cb75dbef7fc007208b30a771c41fec59850b3c8a24ad1427a4cbc352d39ad04b1d5e3a1eae400e793378a5ae8fb78fee511c6f459add843233b63c10622d0a90ed5b8d0d32000e1c04f2c22b4e15b91643c33fd0cd1b5a6b45f85d42bac9cfbf73d7f2f11a600bbc70fd7c90ffa0f6d1dd5bd1fb7baa86f00dcdf466a019070c77f5ccbff96003da086a71dd0a62559e65704034b94069830811ca2bb4022d42de353f63f2c00bb2875f27d05c14edf7076aeaf8ae7baa0e3373d035af24324f6f6c1b802ee00c6173d2672e932e72a8224626d8c89d86a97e715db500f2d9d680930a55e71002ed680373dc04590237758f5a31784988690b08c17dfed9c0d756aa1d233a300c8f74fdfd1cfce427c5fb02747b481ccb4a3ac34c2cd2c304ade9f4e846e2200054b76411004b8997e301acfbc89787daf81d80c6a6962033ea6f6c1e747290019eed6fe55fe94a4e607ccb31c884713033b821ea13167cfcdde7f721c419d006e514aa67b5c1232e03f3f1a188b0805227b3dc84841299dd66bd7ccab16c90015dbb65a721eb4cde17b4e61e7447d6eb2a720e3a3d59c45336f09d71c9d2b006f614f433d2e1cc9a325e5e33f525102bc80cee2bd7ccfd9a5e5041e68dd38005aa26d15ad4d4f8b69d47463f36cd3325f846b4cc7c006e39fc5c021e4d46c00c853e13ccc4c2c0c2e99c6d75561acd5e373ef64c7ebde909edf6ddb54c10c00ee2783063cd494e0fd1030aaaf450a1a8e69f2091b793a5c0c6638d185adc0001ee5214378ec5aea4dde216dcbf5008542a2e40f4c05b4dac4f5928a09d8d80081f6540f943f4b0363260dc986acb016128a7b6a56bfa5b631145ece97ad5100eeb283c4a3ea73b41587e00a4ac43af764795a6e56011108d734ad256b58c70047280ce36d4280909c3d660a1ff729ef6e242b50693fb9ac93ee5e7c914ff100ca55d70cbc3c3d5898818294e4f91290e727c8cc14899cb3dc6fc8cae8e52e007d81c18ba1bf9acb7e1cd88a67c030ab237aab9e0adab89ce299872ea2abad0099b8097fb684f8b31ac650eadf3d41524a085daf9dc7a75a57d30625376ea900d05fefc9ac224985731c697b986984956d7c6f3d10c19efd66468b7cf6a6ff00943d692587cd53ed60c455612c3d286c920f5089966eec876be481e0ed5f3000bb56452dcc3abeea0505ae17fbfc4b7ad8c689cc2eb7464aa422e6a5d29bac0099403692c5852600fe2fa0807461111a87d17f88de1d8c6883fbfb132cc64a004c3af403ff9c0f7cd5aef933c4fb23ed5081f4bf1b20990555c2e0fab6319b003ac6e7f93e23397233d063b9ce1c3b15953646959f53dabb17aea2435d204600b7df7be2297a99ce8430ca242b153180fc9b12be3c9b8235fe5b5162cc665f00d2afce08302a381dac6af2b262807f46f30bfa2326ec6658cacaa3f2c833af00755369b9ba4349a8bd42b132620f7d6dfd2b430537fa79b38fedc9a3b8df1c00ad5c072a46c52951ade77e4a5241e5ddb8c3d2d3d990af3561bf303716d171007089d4c95e2deef8519fdc03a8b8f72e034e8e0a16a10498c628282e1b618700275f88355982a44303168fd7536a6e27654eabdb6848d9ab91205d56b2edfe002f406fbcf575a70739ba4c9202c792ad2f88ca4a88ebb09493f58d06c964a2003876af82c89d3caab84f07abbe9f56e8aaf3a1a393a60eb456f79a387a25c1009e12c530798c755013a073adb2ed0dd144ec66e8293cf6626af81fc520d3d20047c052281c452784b5c891a4a569495841e3a297f22223e0d7aa4e8f4d90d100642a50b341cb63e72883acfcbabcebf79c0a965752e090269058e11c776b9d00d9fe3a4f9733111956bd1c53e397ec76f9578729beaba5046a18aba235b11300842d531a8e809c05cdf3d7a33ec0b5738627103789218b15526e012efbe24c00edc48d8b8e464cf88edd8e3bf3bef55ad25bafa7d76fbeb222cdf2738e7e0700a40b7e0b318463cf491707014c232b2be24bcf7a721db15077102db2c5a2f50085c57cbb8722117d545133189572fe8c71cd6df8ee34b553501ed5945cbb7a008a70687aad09c4c1f2e4aee315fa1de1d37abe2fd47a3f006f7cf2860a6b9c00882e4c4fbb7ee7f987462cbb694591c764802778330696c26c5d07789b9120007d604c7a8c6c3654f1faca9163d03c4d73d08fede7a24be3244a8f35571b96005bd8d4cd11c8b47fa59384a79a6f7398aed6d772a9f08c370021689a6dbcde006b0a38a387f290088f3b140e3c8a850fb5453393fc3c89bd7e944d79254d29001aa76379731b93c9e159f6be337741af606f00c9fb723c3d70761f6ea18151000d90849e323d1545d1472429fb3b905354e98824966cc44369c3fb3af34565007a8389ee37ff79082a92bbd2722cc792ff3c70227c1429d1df733e7c834f3b00f83c325ac760c52ebfe4ee638ae6cb77f45da610b9d39043b307f2c3907a7f00ad182bc8c17c4e3a11d19faa779b547d2480ff846522e33f0f0c49d9d08974005b82fe04789b847814c210021c4b8cc4f7b1f169a9766f07fabbfb08673dad0033d0fe7c5ea41187545676e5f6ddb46cd2178baaab4e62a336d6e787b87b3000e973953cd3c8ffc9f51828941cbca649de364b71428704f68420a862909eca00fe54d5d2257c12b31e0b772590a2902d468cb5ec85fd26784a297f00ef49f700a5cb8fac880d254d21b83ebb10a4852a1e10dc4dd8991eab9c621415d6962a002da59d1bcccce5e7dfcfe6cc3296bb6371f0a1129ea7697825df54acc2c85600c47521950742b2df20e82e49bbc6d82876911343652f997048c1cf0bd14628007a6d2540a51198cfcef1e318200509d671799a00766025bc30a26980c083da00174ef04177353ae29a1522c9a5b3ff43fb082ac2e4cc8c53d5ceb34aaf71ba00db897beccf13683f23070b932033196a509b8ee62c11bddd5a67acd495e70a00bb1c9f8c0f9d041341564ec8ae4aaeb548e5d96298818b028a71cb29374b7b00d95d8c86313a14dd3dbfb74e246adfef78edbbc1383a86e1ba906c406189730050491a5b1befb0e3820f7287b2061172fd51804787657003f2618e9c7158300065a4f0f8c9d8bd974eee5c3dba06caabf71c775bf5f1dec81127e6f8102dc40073d37b824403de02515d147f398901d3531db682e9c489c6ab3519bd266db7004c2e8f706605a246604dd298c92c5d62cdd6eb605bfcfebb292c5dccca8eb400fbbc876c40af0f4d6b69839167150b9e531dbfe68d88e091c1e717deb9e75700c8ec6012e5b307f2df4baaec48a9811ee0ce8237039a4ecd7792bfe304b52e000c208f8c81c4bd1738ac2fa5ad79d9cc5fad37cd2c05792bc619802f3abb050085a571a94ce4894e276100327ffce5effca01584bfcf0162eff03ab904b1e600d1a03111750e0977b61f860d56d2a1801e67e46e19ccf31cb061d5e56ae68d002237ecf6161cbbffad4c845798216098043d26d6afe91c7d1bce96316f4fc800caa7c0db7b8362181f280ec0fa0014f5610473cd7d339d3b2a11b978fde9bb0072ea9fb71d442c17a4dd105d29528081278775eb86dfa54d895864c0d16c74002bf746b32e349ced7d1bb389514ee03dc13eaeb77ec72652ac48caee96c75700f5aeaafb8784e32d3975a1582a2a4b316022465aff2d3a8d365a2a8379c6530080dc6d6c1cb6b8f0dbdb5b92fa67a3febd60de6dfb25d0cf75800675ce715e007b26c738847978ebda93a76b18f1c1679e85647231c8a99b92b125ec61831000f1750389e001dd45a4b04604ebed0927f661e5179a6a27f8bda35191e29b3400eb9003377f67de461014ca2a79df6cdf577d2e64d0006459216ed4cfbdebbb000f6ddd134d26ce05420bef6ae55319ff414049c282d70e9c2febd8a1aa425400c248bc7d13396f4dd3c2b217eb0a890bbbb755962c972861f0259068d6cbe200bcc55c5ac66f080efed3eede871cc43c8657b8eb81082902478bb3de29fcec0078711be086879209c0069bed1ad47ed96a3094476d3e197ace028e54c29bf90087b5f9632593c411b59e73991b8d164835508eb45b62dcb82bd12ac5c828f50070aca9d000878704d40047dbef97daa3ff8b16d221a940ff3e338425c05b8c00ff4f46401813cf6bf87838a7657db80e9070f64763861ef515acc2ce46b4e200a224d3ab95e0a05615523adbe06a887b13516f87cd6ed62bae35f92162a8cf007b133f49fae570608fd4f40cb4c729c9ee61440b7ccf52edc412b3882733d600021017700eb53ba31fdc250f72d213541e94f41f256670de13da5a75767b1100b38563c108cfd1ea8862bd4b35b5f770eefb290c75f9c6051156b5fa7c17d60040799d25981f9f642c6dfa3cf7717ef6d70ac23fc99996125770fd80da704e004590c90b174b237f095fa89dc9da1ceef4e45f79391394d25ea81ae3becb07004dc02fb48a8f0ba7e38f8fa9b9e7c2c93700b7ae1d424d2c1de43d97e95ee700f1f8a9ac4e78db58a0b9e2e10b21fb5c462803a21ba3a147b0463f47dae12a007cebdebf220994e86de03287a410b8491fff899aad1de33db3fa5c81576bb600fdaef9026560a2ee651af96d130dee9a367f936245a372822a6af972ac9c79006fd5207228c44621a4adba861d67a2ad68a6ef1efb98676ca15ce21230eec200a43980e947cbb18ec83f435db0fe8feb2e62d51a000faf399f1da7e3fa8e7d00a597bcfd96fdc52b24d29f67d21952b229b5133e7374be29bfb42bd793c6d000b7d8a4f411102810ee110f55314debb1982567ce2d817dc7c32c093923d4db00d0de93475879301c29f5d9d1fc74f011ae342d31b5648fadb338198a55bb9800d5358ff22f9be996e6d3bc48a553d829d578246dd809305b45d7dabf1d7b09008c46d1083385d1726bfcdbd3bf9921ebee2dfac87e5b642350689a6a4bf3c0006a28d2501d1a58c76fc4d6dd8a28bad56859cac0481ea248ba440df419230a000bf730432ae8895ebdc521c491d83f22ca6389eef7d298ce1c1438bdff990c00be1cdf87a3b4e09eb96d1939296a044da7abe6f3304bef25d6633f04a8046e00ca5d32ccaf571be350054578a1e6239f82fd08da59f32b25dbe28d45a54f8200cd7e3a0753cbfba240742df4daa07835a893a0f38749e2c8d83ca23ddf706f00cf06c573f00e74913235a077f7a300bd4241b8a9a9a41187a20e1c194e32ea00417545f4bab79f3fc16008a003eab63de427149a783c78850c2e1a3a53774e008fbdd9d95b5f51603ad4b9554d4d51533f0b5ee68959c764a08bbc496047c500a5ea3132d5479b3482bc6b50b500e6207b827d4176bf3281a58c4b8964f41a00d9a32cd2d8daa7b92e5ee045a03aa4b3d80850a665177b6bba31d032d2ea9d00de83831819958559d1bbc2f0fa1067754dbc3dd9d5c0ff7033ea6a951aab67006b82d5f20a6602fc587949b64729246b8a643f356fe7321c2170b5c106180d005713c73c3f13dfb6a4b95cf74760321d784ec9cd4a3f4378777a1c29a61ecc00e6b2a5281b4b4c4006ed39bcd7c9835f409a919329f7e12a1fe5acc7e143c60092223f4da10fcf4b3607f6fb348cc1e3d77ee739142fafc3535d40bcc8e6cb001d9b9ca26a2b4a47c380bb8bb37aa830a44f46e0de279343bb819332d0bed40014d5bb9b42ac0be798e00392b63b1b39e469b6d614756fce91bc64beb5244500973b68df711c521f04c9ab1366ccb7e71efa974469f029b82bdfb8f32a3acd001bb430d8e0476605e18f175edf783ce6a7756799f2758c62c984b5f0e984a7008e09996a6d10ff1ac09e9655004f4d7a70fd410d83312ab05b49ae36c004ba00507635aac4d7b891d6097c792188c6a879bf2b8e1b176ef27046aab420866500da1653825f7b2a8f83170c9a853b8d8b8629b2af30b3ddc37642c27b96164800e8b3f84608a436a7c7b055b0df4563190a05e4c7d8a8c705d3c52019e63fae00202ebbefdb8b2bd9583ea246b782063cd9ea112c84a8153c2d790fedd61bd1001cd2cce30aa284112e3a6a844bf6fbd3a3cb2f140f5693bc42b20420a741e80018d5b9d149b8a5a35086ca5d2cc4983989f5c8036f7c86b74a309369fb82ee001cf8c341f916b429d6101d27080b3acfff14ca77f5453d3c58aab23b12dd4900f9b9c79de2a2ccdf97b7af95f015058ea5d407cb2053972d8d04dca3d898620074991a56cce1cd127c1d50caafc359b20eb7932d670ec6b7037f52fb31deda00a54a123c4525c350b6e2df0ed623ca80ce33fd449787f8868a20f7dbb3e722001f3dc8d432f2c587452e77c6eac8a526dbba22109c5576cd275833ef57642600f2e8cf048cb97c56402ff774ce800e8b2e2338301870839ad350614327dc060055b037de545af424579eaf39bc9e58566326d4242866f984b3b048b3540809006bddbfd3c865130ebcf60d9e90ceae0417a6e7fb0e0dd3ed870cba1a8c05b6003e869693d8b16b33387672e4d14d6d9c180c5f088c2616686be7f84de7f2e300850e12f7b736b2e3e56b177d2a8e70bcf22ff3f0658a5f36e673f318e8008b00247e6d5f86748d15e6adac333675906cbedeb244df62f10ce61e859c88c0ef00bdad36ec686e96235dc2477cfab0987b803e8b52bf6061a5ddc419a993548e00f2b87469939bfc89fe6225290d3f05fbf691667e8fb7411d48f05541945c4400f9da36f7c69129f129a454d5f6cfde06e7a6e722373452663268362b5e336d00ecd848daf66d7c2fedb670020f26e213bf3467398bd447624db575129134cb0005703b0cb10456126851e06cc611fbd3e3ac389f03a2df0d68ddafc55cfcc100d3bef6f5bee4f14d3bcca02c52163137e53dcb2b8a0315711591dd8b84622400e7930e23e27c8da4ce024c7d5cf9df9154b169722b1d9f6f3d00862fc4588e00f89835ca27441d0bab037eb636cb7eb684f5d126c850d0c68c98decb692ac00030c0acb9e24f295c0dfa49487a22d07166e3d3ec165708419b73c56031bcee000a9b7c37e49dcbde86d1c2d8fdace230533c3da287c56e6a143da76a6d824900b01e48d9ecb841040d4f574b9335602bc6a4d3794e263bfdda4cf20b2fc05a0018499f82e25a51e27df46cebea1fc78f346b5c05309d088f0da6a650d5fb08001aeeedac7d5e0ccdd67a0ee207a54059d8cf970842ec118aaca4608a1338180062f916b3fc04cd6f5508ec8e44b7cfe6967f9cdf08ec0388ad1fa5dbab37e200b833d3c82df45604a65051e64552888769ccb51d4dba4760dedd0dba7ed0170084c4c70e5be4bda029eb8fa1c893a57381cc8b51814d890f53add656e565040073361525678d2361ff3c91c4423eb5788e65f77c57a5aa0c574c47e46afde7005d95105f0ec7a8e9ade5c833a89f2cde9b80bb450ef1d0f21a067a9c508ca20037a903f920f04bfcd0995a2a83303acacba27c42936a72828f44ee6ee498720088e7816ee9969010dd19499b0e3d1b287b1e640c0f28ce9cce0dfb35f2b7b8001be3c6d4e33c1d217fcdd97b6f9e737ae539de68dc3fe82b04c487ecead9e5008961a4f7e6bffadfb4456204503b6cdb571fd651d3fc29b98ed730a8dab6f400a6d3cb12b903f76987c8fb1345e29268950d041658f7a9cd08155289c997f8000a7e1fce7142617c96c7429be4417ce0a7c0b49acd5e912121d42cff70daf7001effc24547b09a3a2730037a5dba6fead9bd703f5b2343deb795eff0a7955d0049f4c5669db52589c010f4e2406241c9d65c8ad14f69bb7cec8c63d4166f4a00f9f974a9dceb1f011b45af3d2565652f8566bb2e0829094bdb6f5073f2dfb0005a9daee79de035d499657df8ab596f182bf83cb9774c442a67f18e7a30dea4002ccf84264bd8c0e27be14c9967eda9e450a1aaa4ef5ba38993cc1ff4f78b4e00a12c0741bca53149590c77f7b74c5b36d34f003dd549e249c732313efd453b00ea1b0c4adbf0b529968ef12e413e0975894cb32d90b2a1387baf811b7b67290071ba477d7e6251c390d1ed645c56006a870cf540c015d254182cf6c2ecfa6a00347d711cb2da959181625f71889c3aa03ce0dc33fdba0b90815b37812f2df7005d6ca4e0cf89a63b1b493f9dbbdd5ae3eff0208c2310e49a75f6566a228907002ad08286a674488da2f5be6690f4adbda2b5fe3077cd3928ae0fb497820e7c00470f7b585470b2f41b077d1543c373b554a8f65bb8d000e598fca36cbc3d1100f0761a31fcd8b1d2855aed9feca88f0ce3aa81497ac8bd83bc0b534e8c694d003910a369a7a2e3c9eda356aafac15e20d3ad9c69caf337595d78a9e5bd776a008a8fcccfee98ca76f201448243c0baab051762a12e17fc64b5d00d84a72da5007e217ed04c90c991791c4197abb50701cdb7e48d783360e332d06719eaba50001e048e6a6825e7e281a0295872d646d244284db186614e63eb295f86ff656e00c13353f6f52856762f01716ed0b34674335ffcbef83cf9fe2524a6f848df1700845d51edaa86ab5ea659734ef75aae9418922dc425c1796baa10a996325b23008bc95e462e91ed771a01aedc6e0dc5064d0c4771d0040b0321dd990102dddc00bd7f61ff8a029a4519e93e160755e2784c5436fbcd141dfbfece514efa3eac00b3516fc7457f5ff715e24d2e578b3cf54c30ad2e799b845c56abf22b7097ae00e79509ece61934e00fa10d28f4997ac4a1c82bd9df56c4d52d6e3dd1b7ff9d00aecb5b70d37c28fd5cc08a4fc4484c7411512726768f0e3a56d0af46ffe1fe00ac3115d6ec640238da86162859549ddd995a71f5f5637fc3a497684d100a5f004b1a733a58e301a1561b48fae53353e0a1fe15a73c1ca8df88dd78b3c480f300c9938c91b918f22c0918759d9dc4efe86d6d04807d9f885d72be3a468d82a6006a3b284989a9c2c29c6fca5370a130340326c3845c97577b9c6988f62f294900dffceb89bbbf1ffab48a6dbda84b131ff1b00f2bf2e32f805a9970174583b500cdb9bfddc59eaa5530d9505e767c4224c72f274db16dadc0521eface0b94d2009f9e43e37ddcdc4d78e77b12b2d2ab3e69d7422dc2b21e35974f4c30d6bdf300c39f81b4e2dab25a8343a3fdf734e38ced5b50d34bbc56d1f2dc6feb2baebc008a04c65ec0ac98d1dd34c5e939b3332b1294a8e33e261a73cbb3362a7299f300db35a1e5eaa4658ef1843b2a15947f4f283a6c5c2ce93a78012c53d1f4fdc300366248c0d457b49744b2e70d0b2a32b42b49d31b84387b9bade30ed5e73b0a00047c7420439fabe0a8ee4e66af39491ba31e4f86c85ad3fe429c41c8285b9200696acfe066045b82a56fcb87bcf620c59485e29b0e921da1a9a5ef9db34d830037b088cf8757d1deec8c1c63f2a8a76f1146e63ff8fbe41b80bda976fe8732002b732dea63a9ff29588ca3c0472c14a765a93c9ac5c28b4b4bbd8403ca040f005bcad9f9f9c459dda0574c433fa71057bd33ee81d8c5c12290df52cf85692c00710bc9138c59b7819a6b9371394d383d5e2324ac4cf5b9e28ad31b04ca4dd0004bc6ffe48f59db58ba4319340c2f83c3c7642e663251a35c08cecc28fee1af006e2f9b744fbda8fd457009578b9910864c55b11eed81ec73b9493773ce6b260017abcd716f5d7f02c0096e680e431499ae1c520772fafa58e64380675fdcef00373a54a74eff10e3fffc4be2f5e15826af6f5584c8fb38a24f8c3a4996218f00effc6a0f732212f236bb93a0068e07a21624ca815a681b4a3aac86db6bb8a300a14f182b8e4aa5df41b62834a3be22096729be437a79ecf986d7bba3dc380900eb35d39967217b9646ad20aeca77805a074db67756c213627ae7cbc39a3fd10070443432041e0262c98a7bb90cf597f3d996cf27f952fd509734aecd7c3fa300c166597901c65e71eb531e043d1e3d495c744a49ddfb15776ce90893f5fab100b2f8d31e1f73af643aa91073da1e11b590b01e541ee75c914b32ce2f67f67a003fd5d06ba2d530fc6105c399bc65d3aea1846c5e064eb34eb65d4c28385b9e00a6442f437ea53ab065d885d265dc25c620d2654a622ab4ba7468aa6bed1ce4005b6b73956f85f77ee56b3a1e8f3a011cffaf50ef980427e7ebf148848ff131001336100928cc1849a0bf8ba65c2e16fed4fc1c087f0ea35c83878e953a0d6f0007bca2315a9035bed045cc03cc47a8bde6e85f5325c2a792f560fd8985cd5a00cf4affd3e01143cfa44bfb9282e4103ed8a2750b9a7a37647ce606097c45b5004115424d0fe50f9fa451ae05450bd1c71eb73c2bbb419046bb9295b346824e00e2628945330b9d99ffe31dca09a9f16598cc274c1891a55adcecbe9874a9250038be70dbe1e204c4859f63a5fa928a3e89fe45bb26a6ec7bacfebaba8b1237000cbbc59c0d6b8176d0f8e3d36efd889438315b2ac209cb96e15def610f22930057ad475661953707809eacd8fa6439fba0cdc344072625e2702b7925b669e800dc88bdc5ab4ee19f7a4ad65198a98754d3ba8056ab878fead989ac9896ca1e009013ac98b36e2d548eeac4f9b9512409fc89365509ef25ca4b3d085bf654b200dd632623c619a0377f52828bbd37e2151ec7063f4194e0042cc512b939e22300f566ad1250e74a4ae420de7b10172997d800110ef379b7e15b218ad4e7e81c00eaa8196174bd0ee2c64135f759eee3ddf409c8217fbd8a5634ab7c26574ea0007b06805e7cf605637fdf441182925af2f855079e3b1057f89ef8f0cab3c48900961f5248be54c7526de4407b9a7f13a1a77b9d077acaa686548ad0c078e196003d213e88b9c542a24c380c3e08e5e3342b2c993aad36e0ab5dc83a93fe994a00fdc2a2ff320f7b8454f70cc6fbcda44c2f07bc13273d230d30310c3982c3bd000f8be026bf380040523f98720c3315e447878bbc6bbb1d9c5491a839aacad500b6600434804f7be7c4a1a41c9f209cbf4c356e8624ae5a2055c1aeeb6ab90b00a08a5fa4204cadaf55426d3a357b27d797cc4d7aa15fdccd028557ee3bc6ba00ac6d80a4701ba62ea446561e98b2edbc52135ea4fdedf344bcdd7471d21b7a0014f30eb6ad56aac94032dee17f94b3488f47640fce735797c024af52d9736800dcb7f82d72478c82d59a7b32ef6e24429319ede1e9f193395d99c2b85117d2003a183f1203e976be51a3622314447a1ee1e998c300f6507657634a7fb85ccb002671f80c862a89673cb71a2f112d15c4d8b590da4d99ad5f6d7e7dadfc406e00a5babecbe955e093265c1e5a53d59e27b1e46888050a57d3a8649571cf61d9000f3778321ac908acf3dce51e1ee5631623275544a60bd51bdc12463e904b1f00c441eeaeca3d51162d0c49407b1c9c22e2d592286c0108164e497cb012566d0045838446b7be0d73a0f1605e51a35e6e501827585cc5d30c9f969555147a7e001603d60d7f586f468a257dd6a6771cf8fd9ca60b5f7fff0d2e4f99f061c172007a29e1a31727d853cb53d84cbdde7697fb7b2c8c7c9f8610a507c7b3a1cb000068be7ea1df5a3a62f6a360bcfc72fed6ade7ee9fd6eceda40415820919a52b00c10da180609c0d9b95bd7ebffa32b7084ae3134fdfaa83f69b2755a5a8256d00b96331af74b14e8eb44659c08bfc2cc781c0aed375263de5c19487740e4ac900a5741788998f0c3ce8d8768314e54c75578aaa650115e2bcd68f23b46ca20200c8883ad42e7f45f29547f4cdf5ede3a07e2f779114b4ea13a7a3efbdf0fc6c00fec6bbdbfd42c4f1b587f5b200227ef451bcf9610d3952351571dd0a9a09ae005716e7531c71aaf1b9c19b052cd614e64945027fdc1116ae26c992f9fe398000d58a889f21ad05bfba66872993a014f9d33898cc4f11a0815bd6df31fb44eb003b27076405da54ab958190ed9ab27fb81070a65a79a10ff9eb073047d382ba0088f12e9fc4556f6514758dc0f7b52935f18602d9214f5bcf824d51e1015dc100e3598c04e8d5025d5845f57cdc5a0ad7eb554f1f166c35f0f43fa141ac71520056e58897824ebd2b96c4399ad89aeedd45da773fd0833ab8d0ac0ac4111cf800f5b5e1fbf623a44e4c89caac18d8d11a78ad4f62f6f0c61146fc3ed0fc61e300a310591b899b7cf032dd4d7e2958bb100fcc77ed276bd9b2555cf8341809a70032eb1453c6c87ba162952402348e07719f51c3be2a0109db82616fdd99b87b00f67f59583111bff12523e7bfcdfad7ca300bfd6d65c7421fe2dbf0cd504a3a00e936424b8a7c63cd6b12086b256e79ca6ed067900a026edfb3ef37a7af144c0034ecfb3bc62f42b45e43299e4bca964b75ddf6b1c22263b4c3e49bed87a98300b5b896414eca441bd0b2daffb739e9bdd7c6f84eefc5ea69a48930d631014b00db176b3c3896bed2557aa5621a1c0fdc77cbc1aa990527ccdc2134a76fb4b800e46cc089a288f6f192cddee2ddb84bf5c6d133c5e6e63e2d4a372df6f6c9db00be16e7de3527081efb8a199b17e11445676a14a1bfa743cd4c77a6b9faa73d00dc5c7704997de1f8abe4537845249918f9e807bbfb4b6dbdc653d6499a67d80012015356be4c48287b35ca82c4f6544b33da12a616d08b841b7c0c5242d39100ecb94dbb3cde15ce5fd69b592d2760fd0d403ec047ab1c76ad830c8387362d00b08f6e9e403143d0e97ef8405976cd692f66c8d6c84a6e40705c515659884b00771af9a1f3ef3c77616a9d9d41540e416b83db9bb3e2b75d3c917d3de6ebba00a122a182487de64921e0f9f82674db37765b1ff31dfc943be53da2954b489700395ff91f6d11b792577aa1f4cd53fc78b0dbba37bff1762ebc8709a61eeb6b007de1fa02e0084340083c5b8d790cde11fa341db347ae9ec45f3af68d4f6e6b00b2b4c85f1fc63acc3baee2de829cbc33cc4d0cdd626c458675bb98fe46f7ac0021470cf93ac4a68c551ac214d87738af855a58c18c848882685fbf73aa710f00d0d1051e79891a207edb082901a7ea4f2c18a9b848108ed207625e7cf1153600ca150c325b9a11449f9f4edcf5eca0daa2d83915065bbe26d039ca63ee6929005de6b88da77b347c0e3edfc24cd91b45f48700de27e5dd3a104e92b6f367fb000f4a0acabeca6541239be13cc4832aff587da7bb5fb461fabdf8eae1fb3ba500a75f0016f2d12339a70a4f0b791ce73ca905ebb268fb8b800049086a7fd961006575db8e1999aed0d160c4d12ad408bc85f5c5e580a0597e747cc01d4e852d0063617f3b87bf66ee8f991e11116428e693fe507b52ffaf8e9221d5769c0110002977158e0c33891bcb2847dbc8f0a0dd682ab562b0377d9addfd465d53d36f0029f7f7a814392dbcabacfa7623118e642d4f560bcc3ce77896f9a1feab5a4200f6ae42a99d2734ac9deb71e078f34ba1459f0cec9a6445629439017ac84c8c003198f321e36849c9840d33550c28b2a9208572d053db5c0128e7a9f3a5ab4f000e030029807a45fa1784bc415204b8ea5851a1b49ba1b0f8f731e3645ee96e00fb30d342c0a4b98bf2081228e3c284aa5de1f6e81aaa93c3a7f7df251abf5c008c832a3a631cd7d142e74ead203105a81fe4f4fe171dd22fdb7bd1ef4e3f3c008c3f2b3fd6adaa1ac0f14914b3947d07ae27b07d27651b847a5e96e9920c61008952bce43ae15b2ba104b8099eafef0c0ea67e31a4129a9b5b57153e3b39d600402d8fa334ac6fad7e0142e8c22ec186f9beefec3421dbf6133105d82fe19a004f9ca0f9feb12f7b6775a9297eac5e7c2fc3d3e41ee7842228d5d51fd615b600fab8cc31422c7f542ba2162960e155273532a9c390c719ab9fc92812e8e4c000fa28f39b76bfee90a8e16c961d39efb874ecec1eff1b681beac67d7b3e368a009414e5eadd00d539ff2b2aec631e6bad7db2d939325bf259c9ae0667e23f8900a0c4c2ff4683ba6e8084b35e3c430ed9ee10f951669913e839b7741347a52e00adf1f60a995bae181fbc9a4d8778b3e42495d78d72bcb78fbc88573febe02d0072ba393dc7f12a257597fd2ea9b17fd436d4ed48cadd2dff1d316ab8cc4bb500d116bbc671968fefd7bf6450e77e7d7174c8bee3a0f55312d846a69bc52a9f0074ded2e5e57f0f8bd4c6942ab741208614e84686b4c10beec7a890b49b9ce200c3e2981dbb82b15226add2205b05ab547e9653e8659b6cde6d4034480831cd003c12b0bb94c4769b222aa0a267a214a55bc953306ac38dd23eae1736257c1e0017f7b51992bbe9f8199c74ca29434642517572e377c8110a2b077c482d28fd00a212c30a48fdcde7a3eead86618a4d76087ac440255b0808090d7d833ca56000ac7a879ed81a96a55622187785c94e999ac246902b883600049827dd8f825c00d7d5927a0c634fa2108cae79ab70700810217e8eaa2eb0a98a0a53778e63b1006e5c9a60fc26d3d4e5ab34f9308b9c045c7ffac84015a78c41c48fb409cec4003826dbe97c72b7d18ecdff776b7753438d3472bdaff2c1b5663439949acf4b007f071cf6fad7dc0bb77870d14a26d1827b74faf8b355d444be1304d4ee70b200e5a80357a5e7be0dc5250011ae6ed7cbaf0f593eee770c6b4a0c9a6c14e3c10073943143dcd8f19648ca076dfc9f1d650e6392da20769d2a6f605a3200cd990099085358dd809a5c7c54c130f57525531cbe6cc99daeca3d83463e1326f7d000bccc735f681a9412897f83472fa1face911f90ee86279c31a50ef3d17da47e001f84145e90421515e1aa7784ed3e3cf5755d7886ae9271bb4382ee96ed03cc004ffa0fcd501f23185ae2591a657cb965d63c9cf08c297d797f18e72fa86c0900ab7cc58ce0a6c7ccf60ba9ed9ba205eabecf0116fd21aff233be0a1643b9090054b36305310d44062aa171c9b3206b81ade413c2905da8493ca144d3ba0fb1005c605f0e461d290a7805bba3b990779d4a6dd7f855cc5f1d6ef5869cbd712000a386b2274779a403be1901814305ff339d75ca3532a888ea70c25a5372078500dcda2f1c0a7ff5abf368c7cece1cb5a29109d653fed53d2adb4d223a6a0a9d00072aac1eb3afb5572b8b82960760862bbfe378c37103a46911302f1ea74d5800aa57b1864b43190ff945be6042c61945222b9a2a12567a77563207ab3951a600cf4e45dfbb21662b73fb1b92a9360beb61497a4e0338d0b861393d4630707600c48f4da20f0deec4c9f03e80f151c6c24a3f37d268ca258ccb24a483daefd400271de815d4af6149007d0cc2ecac4f416ab42fa10df1c0514f15362803c5ac005ecc83c4a5b53f9537abb85249c590347ce0cbfd68dd1ab7b8990707002f010020d6401d5eee19e220d43430ffed2a1e320cc1af6da28e26577432ae0056380099030e8b4ffc6008caf95aae2bf1f9559ad08af926fed01c6246f71adf91ab00ceeca89e4d5c3d3452bb667d14dd0f099728f01aeb802a9ef72365c6d3396c009cc29b316b2411354be2c6ecf74dd8e60130bc1276a19d185706888436be0e00b54ae3224afd2c9d571748ecf33378e714a5981e4914f73842753043a047c400c9d2def1b299934fdd2a7ce7c666536e1c934efbf630dc552b30754dd9bcb5000e231a7113c8345347ce1172aa6ad59e8cd2faaf42bc50a666b04210455af600876b16277e219f65b6cf3c45b0bca33c4e8c98de1df56ff216eeb77934fcb300e620d720390fe28ded7b9c2aa0047e1d2f97616fc9377dfd17b884fa14a6de006b3ec8f3db3bf23092ada8138dc6c4f7cda5d34bb030878244a8d20c9731780053e8e1082da049bd1e56f167b6cd5b8c1dbdf5d142108caa6661715c2b4706008a2960935a6c7451a2e28384870bf46bcd2b1982add24893021332996879510090c8c06e33a868257a71a7d1e908d8732dbd863d1570ba09bcdae39051144a0042ec84f3fd9cc396c68ba76ebae2a568c5d9c2ef5255add7ce7fcc85fed89100588076671b20abd42d0f1965dc0e0a02e441713c7e36259b47bc977b0bbf31009c9f2f007623ca2abbad8b3e1b2649afec24600e53beb2847197740d036f0000a0559a2e78e6dbbee720bcad36e89955439a66beffbfebc6a90c218a7e6e170045e3c7d6353906a9780a68037db48e358fcf91a54e13606b3f2439de336ff1000b8ad804b79f195bd71fd3763c1e28a20877c55ed01e4829ef078b18a1df33001b487207833f3819de7f870e99291105371db278af5328b88f59915250dffc008b8b41a7ecc5334a4c27c0caf1e9ce4ad0e411b7c48cbecab3d718eb7ceed10070f350cbd26acdf6c3e8e1ba1ca16c3ae29acda8f35ae814bb271f0ce4df92001ac6c44957089b57c1c3992ca8916e98aad28bf89a7eaa2a74f43082af2d3100cb51d6ea54b9705a221cf6e1abb9e894ae46c727d1847eb594c9cea1a6f02d0047deb350cceaaca8a720fa5fbdad056c29bf992854ed41291113dea700b8480027a4eb43e38c080d1b5c082a5c4c2c8c5fcf22ba51f37754839e11f1f435b200e1f10d8fde9997f114cd36d967c94ee727da72ef5b2b5d2c2b6e08a98d85480038f6eebd7307d0b83f31e4d49f2f00ddc78b9d4ef868478919b1962eceecc8008bf2cec0d18318e2023d9f84cb3bacf847319fe5235f1adf8fe746b6d88f4100cec448c0c2b1cd16f447bb07dba3939581befd216fc77dacffc7e69aa5dd9100c7d27592e986c240ae14431dd7fb2709bfbfa66e980f7632b76a2cff798ebd00edb182aff1c10e36898276f4634c856ce96e8b531b86d852e341d24b2c3617006615f61c6cc58015e879f2d2d5e5be4a7b7d55c016293f960a7709d3f981b100cfd0263b1b477fefe2ca04363039e7efe1719751bfc2336841a67b1fa4727000c365e0c50f2435244d7ef02b8b0a6b11e4a9920e92dbc0d398ddc9c54b95c0004306333a2776697fee621cbccf6edec722da791cbaf26580f9dc5589c7d33000c72abaae3d5c3ccbbd6cb19dc97df03bf8ff8a2f29b054ffbae2fa807e2fce00b169dddb71a37d65243283850e26340cdde73270f25cd697f9e5fb0ea0155000976aed56867d2f5fca587190f92ecfe1ba768bfb67ae65deab2cc84298499200e168014c1daaa4179232567a493ec4339e202ad69175660f74da8036a5461f00f8e56bc2df878b6fafcd883c6aee8fdad9041a57a69ffb6e1b8153afe4254300497d927c87b8627d62585699cced7c3837dd6f1f1b7fa97a2d2f0485c3d6af00cbfdb2225a21d920e9bce0314d2ce5cfc87dd6c95b16777fda2e6379a6d28200f9240ee854bb1f92bedfd7f656eb6d26650e176d19b7abd4a17bf1802591fd0078996be22be2a238dae0e4480314c5e77d49bf13b74852f4823b310d40a1380046905be36f3f8a05accecf41d6bfa7a0393b55dfab6f85dbfe754440acdc60009c73f5dfbfbc7e3fb0dff2813fba27745f3945324c6bea4760a9bdca7d5b3b005eab9cf5494665ab7a18b06ef296f6c731b48091061649f25924db68d8795900a2bfd8f327db9ae7890e74d46edb3e792ab85e11df364a4cf7375b5e2007da0045eb3d774cf785b15ab8593c15f42ba747a4c7d313893626410d69098d0d5100946b74d40db3e2485c2b663513dc97285fb8a543eb304869e3b07481483cc3001b2de037fe53134d185d79e6fa4f9a8c79dea5d5dab84fb02d1568fa78a5fc00b7171e6f55fae0f62627e4bb2b8f90e7bcaaed82260db1eeba20bfb67f89c50073a3c296cbd0ecb7400d2b20cac4286676487dc1b641033bc5250bbb0e269900223ccf9b1ddadf662ac2f88756575ef9d692906d8fa0fc6421c72dc08806b700027c021c3f8950de74f18ce8f09465b483e7749869f37cc0f20a9149a60c4d00796bc546b3e34497c4e684a3949284f5a03d746f3f8633392e489883e5930d0062ca34458def10adec6161a00e9da82d32eda4f2b638f76ce6adc162f44662008ef6d0f8cf6027369f00789e8874c43d1a9d61575c461830c644f41369e0e70040f51a25c71f839ea7dcff934383c7563bedc33c0e07db0932cc539b5a8d4500e3e64184c7f64ba864720877457024a52834a06310fbe8c090d755ac0ff53f00709357ad4bf005f7b0c0d65d9ce7b3239dac8092f42bb2c5fc161026b97609001766ab410025a527de8f9856a4a88fb2e806ba2131dfe2b1d4c363f880f49d005ac23536cb52603523fb1304925b123f6f97467c6cad41da62b0f49aa3a807006c3f67f1c0d326585f746ae7c39ee87494808affbdbc91b7adcb605b09eb8400229f5376049476f253c8c43be70534dbc24825414d79bb8fbb5e8729db84670009c92ab497dec117504408f277df320b510baf78e069ed48a28b0282c57de0006d02a897610eeca8ddfa8c99d2536e91e08d7f8ec61772dfd68463a210a3e300f39bf43b70f15b2f809c0c0b3d6c471b010fad74f5e2a21d5dea4844d9d3a7004e0e17ea2d78669f2e58e5c77144301acd90728fbaeeea4db62a0c753d0d3900a73cec1305a3e1b09d396142d4493134f02aa9426e3dec5152b138b7525a1d0088ab7710b7dd88cefa21ff2d2049829457e576b2c79d3cb5a20dec0726c5e500f7547ec48e8de9e86a310e6da81a93f1eac0ce8f352876f19ab6e9c2e6876e00de314a61ee89d13a1f9efc05cdc8fdae224934c67d552ff5a570ae96c26e7700164077026243791dfc6f2e9138a3a94f5aa246abee4d1e550a35ba27ee28df00efe300feca451dc4e7bf85687c206b04a2431b6813f84884c7f350115847e20087713eb6e819cf014bc6199305472d193ce6f3fa10e04650ec77d2136ed28000f3817fc325c660b163ff285326a096e6cfa52ab68fd797e12c925c007672f800e680ad044edf7ae18a319d536dc5e9e58d45782282f4acc698c460a291a4b500a4cce226300d0c7ead11dbb9f589745ea37c5df117c40a2da1c56c860284ad0030e1ddf7124b2c496cab8b4e885d68d384b7e9af81c3507b4fbc4bd854af2a0031873a9471d13db154f995c4771f3aea58794655ac7ee6d9fabd0934fde8e600b13c7a97fec6039b671d4a17dc715fd4012fd8cd8a9487b100ed27e5858d6f00599bc20fc1f9d4113ea20fac2c3c9d8ac9774887919aa179a8227dc500f0b20084dbd846f6fe4893ef0a8f3b1ae2cff258aab7a79e19286bd6fb5e8bab8cbc00512f01981ea0a45db5033eb2670b8f4c99a383a977e4b59393fcee25ce54860073bb21f6762ec10af582a04ca49e9399f519eba48d1229121b3e01f19ad5e9007df6176034e9f8fb1990f5d61d7f983e49ed2b0aec0d241fa9f50aff0437500017b6dbf87d9572c3429747758a1b1f44ea0ab755d599ba122f4ab9d85d2367006792ec29c91aeb814a6000f2ad7364746a12aafc3298fd04b9d3cbce9d55ef00e29b4a1c0185a3bbf5e729a8274136290152a491e7ec68b1e48879d03ef024002398d4a057e3ee68c4745b8e5add41c90a119364e8159788dab7366abac45c0043c53657c0dc7e5b85c8bac1c4e7350df7a06e11d6142ae800ad028ba3f1110035fc05d251388b27a428f2a29f100894132099a3f84cc54a5cd1ae700c9d9100f6ba9ca0531a1cb787864a05db1048a1032bbb59fc7cbe82ddc8bb12ffa1c000b20cd261bde12282f5a28d219f598b3faa6de3f88a5c726a7e97a0238ddf320081081fae63b1f5c39d95fbb5820d1774de42174c746d233364a93d8e079c7c0015ea3c9a33c19f119596a0d51d636614dfc45c97249bd43047fea567958098006ea9fa1b84e301648c05b927aa6638c77168a975077c1e3a8bd9300dda042200d1db17a8de9cb9dfae4904a31d0bf3b9a5f5e64e8c2bb5582fbfc27537876e005131842fd5612cf587be02776edfb23dddc32012fb0ac0a64d2cba50f3ae0d007bd613d373ffd260bb3bcdfaedb49fe5019d71d6cf56b94d147dace15cb21c00722d3a108885ceaa66525b29c208d7b791b23a3d4a32bf7f6db2523dc99b7a00020197a843d674e27558b6fa4eee5a1b3d7b0e422689a62bf056053f8c33e0003937ffc58f732f0ba027516e4fb11649aec1d933da02cd1b7861e97fc53384008f5599617e81fbc3fda191d6bcd882efdb2874dd5203bbe8b8e5bf9cf60fdf00e15ce5b1675829fa737a4eacceb465ae1d8d36e47a86b70d38da80fb93f752007375ca360b15ad0907cb9028705bcdc8729d0ea22ee08c6bbf905c4d538e2600c3c509b2460aa9ec9def71561fc9523b6f71d6aab1f901cf790a7fe82e4bc9001c2b6d60f8205cf78a85ed0fed6cbc8a6dfbeeea289a1e72bdcc0b36b3864f001a2a041dd946fac3ef5f93f92e6ac0664a5fd444746a702f8d1b92de654caf00673c190a15bdcb2ec1b35b139f1d1ea8180260799ea20081e1bb90ccd8115900f807195f1ffb1554185809048d8a0cf90d53cec597961dc710c889001da4e000224bd92f23c7d5c245134d28242c962afae896728827da71b8c5da6552bc2b0095c527c80e90e9ec13eddcc083a7c696b8bcb2c756144af0b4db75558c98d50041956cf82fb33c8c30b13d107961c3236bcfcd15b4d2c65205a170a0d3eb77001de7334471e4769c6e0ef9a4052102918972433a7009dfebc639f0788c5fad00a4795f067fc5866921386fa367562dadcc5f95e83019e910d914756cc7d8e2006f410b05b038cb1302cf53adaade003aa5f1ad7832bde0f29cb520d9d5ca54006ac1d300aecb908e87b44ac108ba8ba808b808aa30380017671f6457d06e1600bb0f76690c251c5b414380c41a24e9a940228d208cb651faa3eb6613898d2b00641e2983aab388b5455aa6341abf55f91d15a54e8b2455b07acb934c121abd0082a6dba7e125bb919ce6afd0cdd682a19c0d9ddb21bda0e36edd9455d4b2ad00c5eee6a1fceb1c0a902c10f049dd8daccb31988ba0f7f7dc461475334e5b22005f9ca86c5d1c02235253df17435a1585d54f79d8a15b0a4063aae97ac8249500be7a32c187037348ba10bdae522c03e9235ef5e122fdb0e5eec0a88fb854010040da616490ba27ea9c728b85d5e2d6b0ee09a863cca9608e19b19c6ef9d1d40020268ef86c69c306aafe0ef6d2999e218b218c96021780ee6eaea03dd0ed8600796fa4b243389ee0ce031c29043e8494ecdb7beba5b5db4fe8e78b886ce98f004a94572e90b54b8cd8d3003430fa25b651d387bc4ce7a34c702638735738ed00a8df3e42ef32c6601ac7a046730f4c468e1d34b82591b680624f3dcb60a2ba008b7a40142cb24cf2a91b6cf6fb4a67204b03eb4d19d1b77584d564cf2ed87800d43fd641cd86ce06792ed1f091009f72e680e5b33aa2c8166fca864252513400b74b821e49b075e04b462992a5a2c2264b2b02722213c99f48e34280e80996007da383441bcd481e613a860aedc2885c8bf85cf08d67d56ed14106c98fc11e009f948d7204bf869d13b17be572a219a27b6308360bb669751299a64b78900300280471d8e831a57f85dec4763bb4a5333fb960e06037277cd780500dbcd0cd006532d826c48e037cbc8c30720d69744c65488223b78ae902fccf0752c8460f002dec49745ebbcf0208d288c549e276f82bb17b9c78866d4892b3cfd7c2ebe900f8341bd6bbe4e3c6a9600b9b797c627a04708f2a2fe9252ee8f3b85d99c31a00c507ed39c7ee823a0fb5388dab2b85c09f40112e2714588151e412906634d40014c2f694a2b461021ce65fd18aa398830a6d9779804eb44c4bb902aa2149190003186d83cdb6aaf2d2ad5ebaa00ce07cf2a946e353475fe6aad812bff9099000a450cbbe48364ad42e29bb75d77bfd6bacd6bfca6ee7d462142532aa30d3a20049e1f90a16dbcdce69ae5f854f483fa3643920668d49944612a5435559d0a10053f15be586dc46aee842dd8d55f2e64642dbf7d79448c85da12cb805e4bdb80057a85b04f2659c143988e286b437cceefd7744d3604c17bef3676b105727b6002b58f8b84fd7f69850285b9ed113e8a0b05df95ee4ac2ae5ac1c959ed6cf0200739052572ab0b0aa3a7123605b28e3d5fbbe587c3b1fc81f88a8e0ec89f5aa00871325f8c07f06c4178949e3d2d40a6fe448bf0cbcb246bc8a6c23758045ea00766b8f9ecabc276ed604830daa41f9948329bc5b799f68b72c0f939433d351003b46666c7a367eb528d8bcef2d6ffdc9d57d07bcbcdf63e2b8194f94831ab600f9706c35cf01690e995d0937e074fa821985d6604aa5127fd0b7f57ee839990021ce286d39a9e7f6f9238f58fa9c53d9dece7374d7f567cd28a1a266babf460009dc6c05f95d007a01a9d8d83737b8bbdb80041c59d4352518a081ed189b91007b530533e2705c76aaa54a8be959296b23e563b5a20f379f3fee9fec45ba6f00b6c50fafe9f3caca9cee93e3625b3a55be6cddf1a2c1775e1f0ff29658ffea00b563ca6001fce8905971911d2c4013cc154f00613950d81db6e868862e3f7100254b336abc9871a60228bbd0f4605af055a62f7c0684c0e8471acb967096a900f52ce17155d3a7635a6ac45ae79c9eb9332595b8a83c241af3a09c22b8362100e3043e919220bcf4fe6f9da06f4a8ac9c43aea094997fbe9b7d1a2b7e93c880015263d66fbf68a2f6254c6712247dab6a7517f2ad423dcb27877eea4aaddcf007177d7b81be133b498431c1fd79442e4b7bff2e74cac64081eef72fcc71f510072938d75e4247109a15edc562e1f4423bd8339297e8ef9b10ec4c46dd05fdd00e90cf6733b87bebd0dd8e3c4e769bbbeab2697b36f54fde48c866255b2f4a70097779cfa66fe1c6e326838f140edab551ea9ab3f7c0930ef7021063029bcde00a07e3ec10dd3f2ba859ed6d58e3035256c27ae64f8a6bb6ffd06893e687f4800aae559c36694c5f0c947c4eb911ba75185d39ed648de384ebe2cc9991870a700a5348a79e00a572a375c76cc78e88e1dd7d3d1edd569ea3fc61803a6e5c4500008f2497ea7052e3cf9b9adc9e8f47b07f32785185e96fa49534677fa3b4bc400475bc6b4d0eb7361fce69767833cfbc4983ca40563d6e9cd6244caf4c57a4c00720dbf90ed582db5fd650b793e370039ea8c3331e659f6d48c4b48d8896d290046ecea09c73f993922370d1d56c1b0b5f2f06335a66221b65c1298a0935ff0006d2abc3a007206396b64d6358fecbe1597ad26c4f536636564d3285e115b4b00ae696ca858f8f1273eae729f28f470b457cd1d60a4b9f81b6c4d488c42cdc50090a3b92ab04fe790bebc63f8dce8cb1c474bb179437c5bfa733dc13d69287500f134c013912bff4179e667feef10dbf15a319dac6ad2c8053a2356ee02f94b008e416748fadf4c40a21bb47f8102904b0c854bdeb9be41c4a0991f876b79a7001dd7da77ee9597647a0eb8c59bb5c7e1871d66a34bea3ef6cec4815ffdb23200315abdc386097ebb5c978439332531519402d39aae5df9496033772003368a00caba35beb5ac99c4dc7ccbf30d37c100cfeb5643c162006ab7a1d7d4a8700b00fd8198a6b8069a7c907f9f8010540c1919c1c41710429216c8ade8c045c4120083736320ce96d48c4ebe54a1e8574eb391526046ab9bc77a4efa3578c1e6f3000acd7e7e48a3ec51669581d658a309b79860e381535ccc5cdccb40427f8cb600cead15721322b55381924a54323e995ec598b872d39407a714c60de681914600daaccd4b51d3b80095ec4e566e14890dda089462f50982e7123432c54e8cb10025f5d3997177495034738e57d297f5d4f27933ff309fc1e672c007489fe182004b5aefb30542470c676e496cd1b42b20137dae26b27b1c61688d084277e13d0015e2c105797dcd1b3eec64c2c05650b09f6e42521634fec0aea92a8c0a44a300b40ea0a2e744c197e649822e4bb7e30398d68d2fb518710313f094a1a9a3730001ea7cad828423726ba1528a406c551a6498ab0f32eb266f9008a24b83c2ea0043c0538912e8799cae0e07467ccc1de500cddd5d37de67418f21de8185f8ef001d72f87466db7362f38759dcd2a1325beb9e91f168503016037d68a99a52c900a95b5f06afffd9601df9253dfa74aa64201fd49c4a108c48397d72659e9955002060511ed67b9e8b68faac3ff75f14987d8aae7eccb0df3381f4c96e9a06cb00b2d106fd522f5dfcda308a75c2299d01f02d56228500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f1b08d0960141c238395fc463bf31ccfa1d0a21216cb4fa534a780b6acc6b56d2345d220937631e790b2600d4c9b117a5ff4f1b090beff273125289d9a65a7926bb5faa8dad9728685a97f9fb0bcaf99f3189b1301a56f09910b9c7566bd3a690f661632"} \ No newline at end of file diff --git a/crates/rbuilder/benches/blob_data/blob1.txt b/crates/rbuilder/benches/blob_data/blob1.txt deleted file mode 100644 index 98b8e211..00000000 --- a/crates/rbuilder/benches/blob_data/blob1.txt +++ /dev/null @@ -1 +0,0 @@ -fa020004ba020000001611aa000000034277ff00ff0001feed56d1420ee27fe2a5e11539680a339a004bb25733b142e13399f2561ee370566c9a7b1533fbb1fd7bf9c45bde68111d004af20972a34d3988eed31121ad9020360a3a5734e146fae3a729592b0badad0051d44b83a40120dd47368416383c686d86796abcb6b031d4f8871ba79164a100c3824e1dce8ba21fe35754a7d0d2c6d8c4c37d526b67ba3057d91a88a7f46f00b27bb885c310ac601f5634f6e9d6f7c5730efbfb2284ad319997e2eb68d65900053e85b0c6ec5c683da7e728615e42578ba96e21f855c1a337537001fd5bc40063bf707e416db4ebdb38c8a48ef86bc47126524c4c1563e03b411a66daeae2003a41cc79ed8e94029745ef64667b2568cddc250aa5105558b276aa3a245a3300dbc71649b84cab6ee79ac1ffae3a4bb0d81a269894310fe1d1e071bdfb89ba00ce1c2821ef0e30551ecd4ab51cf09abeeea314b761f01f891bdf5e3855779e00815e4b708291a6e1d9cc35dc1ef4629a206adec20e717a4a42f5a2354ca4e3008de7ef2ab714c988f8362d082b9bb555c74b30ab8d9cdd3ad89921ca3d3d6c002729f7108589d22820f3a04f0ae347338cc94bf17a0d838fd44eb3c36661d5008a0b5603b5253c210e6fa3c614047e119368c08e405a4343cad97d6b30ecce000a22a3019046205c6aadfeb6459fd091eaee31af225ff8fee6f5543eb37315003b7cab9472a501121a62ca3e870e231649e6e833b58e76f3b5a61f33b367b700dacf4d1d05d68191dff0c47edf65198c20b04834e0b854302b280d0ecce19c00b253300b966636b121034474f4344834723d2b901dff586e74e73fccc5b08300968dbd39417caec3ec90243aa7cd7ef54e00a4cc6362ae7309c8fd19be1fd7009b12420b6a7d2047bd9f7c0e6fe7c29d898d2187d0c0afa970e9506e40d3cb00427f470c7367c4fe07f2dc0afdd7f0646f7968c462417bf8e39be303f235b8004d5f1f1e51c2b027b2f0910a91fb5b50131c423659fec5e833b29a440996bf009c7c8dfeba6eab6132b8b7bcc55f29ef71385d646d5f7a9b058808c1347b63009e8b03adc33e553d98de1e1e9017c3976ac910a662f277e908084c9be6f737007846e4e4067098bec934c724e060c853b36ee1ff2dafb1156a0ccec963895e00188ffee8def41363e0cb485934df99abbc4bcab9800c0a922f4a9f74048aaa00b2a2b5eb5361f4ef50a13f084f336375ee192632e04a7f1781880f71f8865b00db7dfd640158126e7ef64cd14f1bfd12a86eff35ddad3ee6333bd63d9b8e1400065e6d2e82e6b9e9ac59a118c02aa6d67670c0f7e81228300008cf011df911006a0a6e5b4156ba479edd7f4b1c84c734dba7e157ad2162003ae3900913c14d0067db3dbdffa02113812eb1a335c7b6c2eed10c0b5f5799ee6a83fd0b9ee38b0057cbc9951de3f173841428e42e5a45bdd9caac835e32562c844c0198b1370800da9286a62bc6d4fdc3770c33fec9bd93417e8749ce365c93c0a0492de46f12001d14724b9b599a3cc379522667cb7167a9bf597f5822cc48a4819b126d2af2001d60ee6bfa37daa3e7d44c6cd19d423f8f3d7736894fd0e7e5f43386bcfc3d00fc465e9494d92c70a5f84132dc2677303794e32964aa816282c01b896c509000e7d4f24ae15ff8cbabb34e2b2c2e728f904ab2f65ccba24abdd466962b4ce700b9b71fec11ef172ef874bcb13a342141ffa3a6ef8fa85eb621e84f9bfa60680024b1d0d4dcb9ff2164456c91dbfe309d49405dac779ed817c6ed3fec1f6b250081caf3c47793d742560e99cd8fc7ded219f13b150b052d575b86015621a1fd00d128654c6f496dd0d845e85129d1e628703eb688fc701f2edbe890e6cf8f5f00729968509f66b656abfa3edbe0610dbd700fe90e8a2bdf1aab61c5f94f3b6800bc898d258be0ce512c97ccd819f834bc74ee94f09d7f0287515c24fe2d0631001205ab32ec99f3eb997af0f33de1a150d4ea23a12c00f73c8f8b9844e9005d007cc3a76310eec403fb4d078d03e8f299ede73538e7c4f28a6390daef7009c80036e51be5dd4894a96c4c54029c64b4ee0a71b3e26bf2a309b1a4a2e0b259d000b1d8f11a3261287d2784527867e47fe54cc4a1864110b42d2848c859068d870008d721726aae0b412ec7a93580a262de23c17a00dd23f892adf4b886671ed400c268328407a5ce9b6922ec840e6356827781b80b2eb07da3115f72187f0b90004ee876c6daf22b1d9b05b3b0379caf04616a05b5c33ce6143d60741214f837002227369f6842e45357580171b5233f55f5192acc1ed613ab9353579576ba12004ea22883f84a4d9096878942cd429061b465384b3db6b5a8d2a389a2ec956c0078ac6f47c24a06028cb1e3a6fca3582319b39852551627ab05beef36fa408700aa459f8f764c7b4c4a8e95784441b0a5ec12ec71be9e09cbd207bfe4191694005062474217acf247bc3a7b5668f7cd28ed2955a648b4c48672cf91e2c719e3006d35d7226f9773f80598414eb5447ef59c2c7a282af1a9410e6cd023dfedee00422cfb6dd05e38538766a084103f228b9ed6c685fdb983a7ed040dccb02208005816e95e3e90c627c72df1724d603df80a090dd856f7efcb188e931d0e40af00e7376b6bc7eae7c5118662abad7a45e1094566b404551511e2d27da77d6e0b006f1b6a64f2c7d2b24822c5def2d1857ec7bb8832c04e3e6c4bfd071edf38f400e209abfab858d9894f84cd2810d44e537a0a266f1c155e322f997c6dd41f8e000d4e7f79cac70e4eb1e2f86ddd5245f80b797a557e8f4ceea9c5fab7b96891004e42762fb70f8993aa543bdf5c484d5efeb714d0c8cae05fa7b6f13785343f00165e6e023f81e829a8e11ac34cbe4f110c0805e053dfc23afb9bfc7d55b8dc003b61641a11e494ad1f5200ca65bea50ced23682ad6cd7de71be4edc6161d6f00a07d9820d765e8db86a44a861243f03e9c9f6ae651d8e96b06c0073fc6a08d008fb35490de6f5cd2112fbb091ab8299c8e273e69af218af257a70ac4235fc800a9895dc058f34caf30e3db8d7db76486c54187732ba384197c5ba292c8e40d00ee2d0cadec12e228f732aa55bce56917fe5e681fd703733a6acdfc252383bd00df484d1c9c57701588be949013357587b976b0fcc1bd0c195fb50e6fb0661200a9a5f6f57f89775f314cfd41a953577b164689117a0e37c1274ac6c90a080f00758527bdf8c4414530c56116a4364c3bd212485132ad8ba49b104ce9ad45eb008dadf9bdff3367ba111b62af7968a2adb1bcf410f1d2ced305206b3d6fb02e00d137b2457d858f67454c68502903666a2e295a1dc901b77d7c67a4ea525963008d5d377c85f321224c13b8c9e7dbebb4f7bb0a5a54a49eec1c7c42106c034400ff03f702b37e5b5c8a8e8ff27c9ec3765ef48054e33ddfdf35a78d3568ab9b00a8fde32007eff93bcf3c8d0ab8c748d4ee8105c2d5dd396ea8d80cc78fb795002a4939ee2e8f957be8ee06fb0a741b01605483b142c2d1dfe770c2d84a7d9000935c2eb1f4ada8c9f7e95daca0147b4bd896ceaec0005c41c7cc1c82201655009ed0c70c957b359f41c1ec026cc4ec0f3471fbe8f8e969f232fd42e8637ddf0060db89d4cb0546c764cc01f72b30f3b18e13808fae67ab0e888f399c3faebb000817c11e77db5fa3c2e250723752f72614513fceb599bf04496a87b995209d00a0c8d6df62b44d025bb8d9ec848ceced74768d7cb4750299d9a53076e8833200c29f41aad9eb41dbcf7b560810e63d67d9566e161eb30beabd1ea08ad54df900aea612999cee8f3b0b44c930dc75f4f7bfd7e806abe033342434e672682fdd0022075f81636e85adf8bd89708e56db71ea1d8c400260d11f21e9dc3eab376600ca47660f07a25f86d357fe1297aba050f327087d4430bd56bf5152155efa1800ea3bab34998bd5e9805e6c32ad685a9d7363f734fdb9c995577104153b221700211a25bc376ccc14b67ab369b34d19008e7b1d6e85a76b6a1669572273202d00e359dcedd00be5908ae9cc323b504480ec67c6b28d9d4a13a41327a9050eb700293a0e5b5ae26d993b65405970b2aede2d57cc7545687e951e89a1c8372a7f000f2639dc196095c8d5a8793444e201787f8253c00044e324347e2351fb55c200d48d09d41572c319e8eff5ec7708e8073d742897443b37a8bdcc45a721050a00f290c50e6c44cc5be89eee2ba43dd458d5923b132d42149a14fe42fbfc5775005259df4a551fa5eb1893f869203caf11917e2c4c71e7c7bde475f13e99a7450002622eda5c8463d7329fba14036750fbad21241fb9d96878ea1f2412bb2bc500d5266dd616edb4af5e22705381f69c40a380402c16c123979dfd703d8fb88800c2b6e1e193dfc5832c2efd27a13df0eb984139c3488c1fa589e43283999dd300c1248ea7980ea9e1b6e8a325a8bc7f024dd9e406622527606bbeecb58dffa10079e2f26090e63158bd320d87e523fe61e7f3ab7f2e87ee1cf9adb70b8a65c9007eed85a0f9daf95e74c4de92f24d524decdbeab514cf1401593b15af9b7cb600edebfff0a858d2dbe871a4e66991e9a02dc9c9704e5c9a22528cb6c0e60e34008b9ca9dd8e96895edade244620ef5c1009929417f608c3188c506c06c3fa6500d86068ec1d9c56ad673a4a1b19d236e9e11b0a0d62adc205780ea5cfb8213f009f0aebaf5de6d2ff54600cd80ff205cc333ca6e82dd3792d36f637b0dbcb2100bf031f917db10cab423e8b2a6552740d047c3cc3fe5aac8560703fc1abeead000557d9e3820adb1321f3816b76608316c19ccca9a8224b263a06c886b83571000884144990089aadd60b00a9ee3b521b9e101b05c13db13bf9c28c9806d544000982ceff321c0a6bc7a63414faaeb9c59d7cce9cfee7e27ed8e3123d74037d00c01900145d9fa3152480d538a008f270034ea2df2852f3c0b0f2286f665fc400b3b44709034bb1f92dcbd1fe5dd95cbcad937d7fb81673df416fe085b6ed2d00fd05bf10c801a7f7d51a05bd3b6cd8e5f7d06b3105c7a1a366aa18dd9769fe009e1cf63139685338b654cbeecb0e0c4c8eaebe67f65fce257f6e1ea424848f00ff6ea04bae307d83c74ba29df3474b5926535eed2bc1d273227d04fda5365c00d4ad9a5d28342d4560fb813d0c0f11762ae6624470acf2dffdece5bafe19ee006b0f8fe93e87908911106f1f4245c4280bb0a62f3e6864a50e439f717f0d30001702bfb62449ef8bcff3cb60af28255c9e794321114a28c8baf820da78c5fe00c03fc8a86e21924e74af5c52aaed86684c73694b101806cbc5b14accbfe4bf00d2e127745263843ff589b29706bf13638704d7313356e7348c9851d4fe4f1e0011d8db30c9a1ed45651643d2eb7b564d427416d7bedc3023099b153d5d53d7001539a4956934dd315d8e816baa73536e5254ed82542c8071b87d97f5a902ca003a7e7ed0a82d6c4c3004fbcc58e5eb74c7786811b90cba2f9c2abf986aa0d200b047c3526bf6d1832739db5ec43a2299e1f4b6b8b7108e4ddf51002f76a64d00ff7d7fe5aa9d936489ccf307a8a26760afa9a3cec9a65479c492738f41013200fe07ebd67d5eff46c7cdbf24fa3a7d84dd767837ab99a9d0715d1a164a7b68007cf631f8d2517209e8d5dc8a3e131ca3c9e0a7c66dcab8434b3ec354e5ed21003ea1610a42dd223eefb52e88960896ca69180a25ce5167da059f61b3f0ec4100fab62eba9b566dbd7aac2910bccf0eec0b3bb3b5c04462065e3c14bfcadd760047023bc1f7dabd95fa6c6f60aa00cb1b21abf968adbc07767949411af6cf630064fba2f9a83319184062cbe5f07dea0620e0d42fa645157cdc1ef1cfc2ce380058329a59cd8d908acaf8284dd70e3b8ada39a0aa6db1fc9c20ee24b54609440033fcd8ed33a547db9d36f427ba731896d88a424840250f78ef9a074a416df7005cbbcbb15ad219adbde6c2fe5a3ff507936c3c4c95de36cda659afb576299300647beb4f8e59cfcc59be688151c02442f7c4ec5090c1d75b1b672ab07818d9000e8ca52ac9c04ccb96fc5c84ab54ff288a53c4a0c695abaffd0ee23ae8f1c000e64e0c26de76de4a31b0f18bb43b4647b92b934c12425930372cb9964acafe00f47abf61c99c324674446ce4005b575d5189ce85308614e15b245c144ef1b800a375065443600cb967d504ed25e11e3550962b5adf0c5031bfeaeb167f35270064d943ca4964a0f762c3fda16dccdbbf2c7081adacc73fff07a42e7961663100f504512e26b4207186a025fde4f42538976ecab20c46862ce394e72dc71abb0000990e23631d228a7b6b12c1c412ed62864daea2764575b065a069b0b9be0e00fb76f6b645bc1a77fbf8c3d8d3c80090cd5728067ff6d85701c170e118b10c009e6ffbe075e4e93406b3a4f9ded691eeccae9e7a4e737ca06116eee8f402af00299e12368e1ff422f8ee9f1d88fe06931e47a941eb3f2c2ad076d015485747009a3b29e80f14b128c877e8bc63ec0f920a047f670bda43cdb07c126055939d001aa78ae2cd0491578eb50bc138b4d0aa65d463ad755239c5cd7de898ab095200298d6408b05115a841f8b4bc12fe942427e1487e806a5e932768175dc94415002454a831b4dd45d30571f6f035bf292ac608dde8a6f3d4fad941172f5735e0007fd32b1beb7f3b338f107151c3d058440b70080d7006fe9eafa10bed7728bf0057e16c05273741f6531bb89d2229932b9effbad32bd83c858a207a49ee9d3d00b8575e1602c906c98bb113855421633b07424d83ac07f7507e7f802e1c90510079ecf32949b596eeb49900ab124a1d1a1acafa93af5169523c91f808f6a28e00596cfa20b59eeb0bbd464cf14d23eb4dba54a1eaa4fc56d7934178c5421f3d00e4c182996403a6df315cbbe7319975dda0869aec58f4fe7a6649fbc39b43ef003e09d5e3a5a2c6fab26353086161bd421aa2dc5cb2e43232c23a2aa479e3f4008c17e962ec32cbb84af97164591b08d87756e7a85b89f53dba86e73a6c1e40000bb00467bd9969904de85c46d9af14ad263205e384fa6c29161aaa869438b3002c9fb97df0779e3cc80fbd6ba621cf7f75dc52526af5d133cb73589db66923009b4c8907d66e1aac7836115b4ebfe99fed3877ff0db0484018ca739c24af64008556642515ec6f009ee2e6f1e5d7e42342b07391ecdb64e2baab59e1791d440062f6d44da595822dee1a1854b6b316557a215d2774145b31e92d6e771645ba00dc6fa0d39caecb6a906dafc25a697122d0c338e00f844b69da013b1824cac400789295736933ecf510444dacc5278e0b5db201081699e916fe5e61065c2a4e00e1f8769240973717fc7ca685cd820e43800710aef671e03d342069c7217af700d40d4ca1bddef8a55a780918f91af32445233af8c83f72c99dc25a18e2498d006e5d21871307070a54628327ba20e31e902fefcaef6000ce659df2b73141d10010b74584442a0b3c1bc69058ee45c1cad995158ca20a390e9e08fce141042f00bb7e5380359413760e8335a754e0443da3d399544f56629634ded890c1894700c725c7b4ccfce30e60df936e73b10d1b867640fda30254cac0bdbb3f672f4e003319d225ca3df26bc6245e0676ce4bee48961446fcbb93f9abc48f454b3e5a00e75c66b67c65bbd7631610f01c42c4aac72f6fe8de289a034f30265e56a65200db7923e7817f980f53eaa2a4b8187be8bdc65c6c79137561061809afd92fbe009caad0264cc70855f2c0bd66b8069a4e68193a3dc3dd9ea621b58b31afe31300797a3cab42041d51f428d9dedd6051fb0d726cce7faf754771ad9da6fc4e7700cfd17c2a87f1b1df071e87fb9e3f928eef4bbe9b5e37887e99bbe7144711dd002a34b970200325ee2afd15c16e1e2d361ebdf555a86ccba54eed8392e8aebc00d025baf457bf0c912a3c5d0117d7d5b06e64fc51ef3d95b5dfc42aa4e226a600ea2ea124b6150389d7e2b7ab4bea48090183f891bf048c384796eb067b675700f477cc00552ca9984626292865b4c7f21a5a194799285e5db6aa1108c430e600faaad6605339e19190903e48cb54ea44da85e307f2a4a6dc6d60dedde4a18400ac1fb329a9d4004d1e038bbefc656b767b6e7de5a61844ba4fa18bb9d1481600bd1bd68c05974808155cedb8154cafb635d5376108ddd3297aea4e77dce803003bac0814dcb25dbe17c6ba75e5f14549a08d49cd0a7358601e0b74cf188a06007187d687c18ba0d0fbba894edd4b1f72b57c3ad430a718429b39ec7f895492000000a3a7a863da78e83f72db643da3b42ac8838c9632ce2f95ed881446414a0063df23841c8579ddb8f2c0db6194d12b8cc76670a7919cdf8de2a00c48f0bc00fa5cd8d9fc5af1f526c83fd04636f3c42780f50ad0a1d7a84a71e8edee281200202ad0f6dddf699782763ec02bb90f62735127d810f0609f334a638018162500ecdf37abbfcb4610bdd40e323a3e99ad058bc1bdb4fa867f66293485d3618300a121152de9b05c48c90b8afd514f5568cacb5f6969e24b022eadb6b66e69e5003aef5e27601c00f8b0c88c2fcc4b81073eb3ad7d5fb9597596287e495bf4cf00baa738b3dae8de89e8893bcc730df9b498cf51bdf77ca4107952d8e83f0d4800859b35bff99d0b208307507396a7f28c3a879ccbe4fbfb368fa5ae5b98cd1d00efcdb209729238a6fcdec512433782f112a76c72f24d427d2bd78c14f6efa90052778d6b23fd0cd1fc1035ab564574d2ae0e9a51ad597449257c077d97119000b0a12a8d9099bbdf0fc8437095d39eff60e7cdc032d8825af63ebd21713be40009b779265e91b4afeb9ddd4c0b61484adb3c6c30b164028c6d1e2da63b9e5e00c54b6b3d2756f89cb4841a09e8476de0657e6cd2ae89bf28f2bdc9b0430e75007846c923d11526deb829cea5cf8743ce8989c28af37c91922d74c1a86c522c007a02e3108816e68c75085548e1c7bf61b820f92b215864fcefb65cf62123cc00b17220c27fcb512cc93243fd07399e98e5ba08219527de53bffe6640cd7cc600bdd12bdd4521515701f18fd9e28ff7510446f273cad86ae3a98f2e21a6711900959a27edeea98b38f1109792d23c88a37541016b20553e03646e183399e542006884c3023707b44849c49536ae9717cfe28f4f80ab951dbbfc9b1440fd9e0200483914367b47709f48a43bc5be69af95986d39c66955f9876c624284ccea4500c3bdaa9c750196a58556c16b831e3e1405970a1394bdfe6531705b6d2a13d70091624fc3821f138477dbb92008f34c58750d86e3671d9e1043f6c2cd585f06007c712f9a1da5d43e3681a7ece7e7195b4752eb8f26b946c59f8e6abd98b09100d82169c901fe66bbd7e4aff0d7a50d66f4a9c377a9390603deddafc75938da0038fa087f122e0e11598224bb86b1b752cfc20910736095c17cd3ab0e43c6800033c2ffbbcf8fa696a4b34098466a223b9b47c487fc4faf09138b4b2d4708cb0083c3549f3d5edd52f442cc209f609ef002cd6ee22661dbe4be317e5b500bf800cba68885de0a9599f12a470db197070b43d68fd9d0b01871b65523e175c8f00081954ce1145981988fe4a54ce8b8bff331b32480c7d549910fd05e7fd2fd3f00b0f6247b0eeac990b8b7366f36bf5c53bfbbfa84e55aee0fab9615a7dc72a000c8e5af68a6ae75c16aed8c54991914a2a58aff2bc011ca6add8b0000e351fa0091ca6a0026884a361d3b788a4275bb05bd3d2df031b1a25fca45baf8fe5f0e00db79809fa0b05d46e304b676238a0a688004eabb81ceb5d04d4806a654aa030070fd6bc24a7160d888f722e8b155e219f06d33507e8acc7aeaffa07a59e809001e8ad71168e9039a2d55223e2cbdf97500355ea1623fc44034d1bad29215440001f273ef3fefee536fe41a1cf784a8b6131963cb06cd2817c47233ad4cb71900c96b76f6ffd20f257f94dd31e659052ad1997164cd8e9648b05740ac4cb09f003b265915e20c0b09c482eb9642d39257b7ccb82df0e28c67268702dfde1f4200e9eabf3b1abec7b1d60e83c3799c8b605eb24b6a153cedf2db969aefb46a59007e6df7de6fe3168dff0ebcba754bcdd17997b90c36f78feb665cf404a064df00bfe3b561810138e7b2c169b0cb094d7710e6e47fc4ca6b4d4cd4ed41701bc9004593ca6b5564d236981547b43c695637d959bc32399531d57a258a0bcbecc1007137a1deb17f4c1fed10bd2cc8fa42e01c87496a9918cf6fae30f960fb4091005ec60a2d31e2ac2f05223ed10d91cf14b62e2ee7230cb315ca70bb0bcde3d10057f6371680289db1a69265597200e6239731874eb26b1338e14992cd01a4a000b640b2d4bf063d18727ad72bd9d68bd25a379a2ac9f5744f0798fc1787434a00893c98d635c7bfdf660c93b82224e24b9afe413846823f24a60d4ea4c77609009fbd3bfa4542f9fa20393c02b3d44666283d5ef17b5233fa5d117c21eb4e7000418de8359eb28aaf6829f1988001c5461ed9bdb7db2d8a03d8545b3adfa1d400071e1b6273991c4ad7936bba8d52658a8ffb93d469d38b552646ceb523c9b500f3c3a71537b47a7797751a4ae5d1707f4c27e5e93ff778a11e2aa7dd4ea250000882c9234e597710bcb71b741247f3fdb316bb08fa4c13d8aa9bd5af90876b0057056ab9a9d73d4e143bed5e7780c54032695bff78e3da7c66c9587b785f9c00541ff2ce7fb0e4b18b90582f0c2d20e94573a74c62ecd959cd061cd38330390055b64f95c6758f3c67503b099a7f565ff14a8c04546bd76934a40bcbae75b700b5aa2cbcc784a7c5e30972c1ec09ef0cb4007a7314befeb8d2c929fe79bd41002e870ce65370a29a3d01c7949b54adf31d576c58163bcd0f12a466de88e7c400b22356bd5732f25955b56764cf47ad955e496736012cf217632829278f3139004a647a898c0303ebdea80745a39a421fc23636de223135325fba66b9e22bb100bd2fda3778970f410405c6abd1299fdff9d55d8678097ac63f66cc2adfe09e000159415f0fd4bba82bf210d6e7b427e6fb64b8dc13f1754882a2dbb32f998b00e4ddb9929cfc6dbbb1f4a1281412701da452fc635ce8b031686da099e5d97000c68f6fae7d7f01fcd462765aa65875b7c5d425feca92e983550496c38dffe500bc4802f8b19050a72eff3dec640b72ac4005bcbd64023c1e62ccdfc22833e00041c23ea43c6e93ef9ead6fcd4ef746c989c43ebf1b5bb1193b57c9546c129f001509e3a8563f053fa57036bc9857e41ae1e7792fb43c29c9bbf6bd79fd66230013c3e208a07c2eac524def8656a1424caa88689fabaf2ec1f824a026143913005203fa0ab553a9ef3f9be49de6b9d0b3c7cde9f4d153e712a7a590d54454af00fce73f62dca5d4a79ccdf2b0083d87dbb7e0ee78506bf2165c2ede1996b3e5006f9fc915314955765ae4fdfb56f1a7b7a6c14f737bb556e66b31a2a2c390f000b9c93a34177b485cba0ca422136447754a7a58d499fb95df27963cd103183f00f12fca5e1dedee1d77e8aeea3b0c688e63446f6497ad1668f840d7e0ed07a800ef45d493d25992904634d9bc1aa63c237ff047260ae8303a88cb4c2b5208bf00b6413601b31172170032484e1d1fe5f0faebfe1e0b31bb5c803ce9869655ad0012faf96f782ab51ffec48cffba54ef4cb89fc7643dd4001d225169597bd7b2006b106ec951b8e43d38da0d7b34941a165e8ba311e96bd44a23feaebff6fb54006e38b8691872d6f3b159f1bc383cf6b996129995aa65b416d16dd8b3b462b900eace14991d2e58c9cc957e6e043a5cd6cbcd95c9aebf814ca761286e874fde0095465fd9a7951cd56dc6b22e9c403cb2d75c39cb030df1c6f4601fd4d284880060d4eeaec0784514147a0098d28ab9e48f96acdf8e0a8487596405708c05ec0024e4cd593e96fcf663a2e8e7c23f5f3dd054122cf8c3260b2fb58bf93a157e00e6e62c41666e5a5604df019dac6c49c6dd1bbec7e39095a878408069532ed800f1f81b342347e8ecb7cf6b5b31efa39f9c5d8ee38fc127b6adccdad77d0b9e004dbdbe06f5b9e8ec5d6b184a2d81ad5bfd1560a454aead87e20749acc5dd9000a66d992768898e992f99230eff7bd13e1c94a94a92f68795164ab93dcac8fb006480c9413244f089f35e8fb71712cbdb774f46730d4caf317cd7baaf97239100bbbf81c7efbefe5e059067712b065685aabd9f3ee59d76db97110f926e0e7e00c76668cfc7fbf61ce7f1830e28b88ab6b7cb332e3520495e3f2e022b4418f7004a428ecd8a69edc2363f4d7f3da4420f4ccfd00a7132b5d0514e20773a1fc200578a173eeb6d4260508454d53d16b15fa9285ab47a509baa9cf1a4d8e202ab00cd01e3dc22f9d40e0e321cdc3cfacc1178c68bf4baf4105b4f2f0e849f563100dd5c6e526f2788eafe9095fb23288e489f648cc8936182b15d46a69ac9b558009fea6b762ea77e0970f98d7b4db3ce032722a1e543c06d6a6bb8bf57b2f6ea00c34965efec7367bc26f8dc7b66fbe0d053fd87b60002d4554f4437bddd1c3f00d9846f0f11d41aa3581e78a3475380acd2287d68ddea2072950414cc2ad73a0037d45aea2eafd149493bdad64873049aeb5281dfb288d9b17c71c92e9394c7003a31ebab6fde279a59e0cb070782db87fc686e070e9d24bc3da179fba02c1700b8948150e3a74cf4187a1844c8c70dc6bff9a6e8d13916ef85bfea278d9a0600fab6f9946b6f1c40a8a7f270539a05217c205a126ac8624b00ee016bbee0ac00e54537983330f525f7585bbddcf5caac45380d0b10ed3aefb88dc86442d6d3001564fc928365209dc55f13f063c93f2b6ca4a2a9c12cf0753d646c8e10c6bf009f1a783032a447c943eb72cc659116631e9332153640df5ffbf7c6713484e500d66528a6b47d81da6248de0d9830d71143d29153aeabf99782810b7227f3d7003ca6556a08e2e4238c9e75c4f6ddea0e81facb516d62fb44d561983399410a00fe6eda2e5d5e156a628d43d9e65fe67f468517468f1966c5d3d52ef098c34e009e12c2d3ccc20903c41e49f4aa99eb3a9328d7ee6ee12939634447b6bdeb8f00a684e6b618988f36cf99c7166ee1f966c23b1b9a8f3d81e0abf6bdf2b7619500e9322c94c05240e4e04dfc799706f9375d8ccfacce356cb6c3274c09385a3b0054a6348b03dec7f81a756f2a52731bf24846ae0113ac41f17ce2d68f128605004bc73100cf3f62e8dfe51ab3cf93e58111f38f5fb7e324ac2f004f96f65b3b00335c5cfb4abf4c690c9a8babbab1428bd0a5cba47efcfaa882495d9144baa100ffe5a932a71f493a45f08fc9e57a6821a51452b8b03eb66cfe0f7bfb44bf0e00df801178257289abad6ae3b6869ce308cc2b0e39a444f8ced8c55714155d7d00bb62c281ab3ba2e9c228ce1bfb8f98cc0fa7b161f669bd642de113e55e354d00f051b5afac283c1c693f1f1f666fa473fa6ca32274425e8033978ac2c31a53002dc1f90ab914f5365247ffefec103a0082e8e27c2ca1fb7e89c476fe0b6d95005c24b8b25e0db2c87e2d428baab9a926089f372da9e2cb4384cb9bffe2172a006e8145841c788bcc3b24792c579456c619394fb7ad47a7f8dcddc58b01463e003627a67a691df0d0f483c94afb8b93e17cdbe2155ffbfe6bddcdeb6c3e6d9e009397c41cc5e1fce827dcc5a94cedc653c4566489fd094b4997314713bc9c01006666fcf32e0bdd8d6df32357eb102c158e84119483c3f53fd2b62e6c966b5d003a05e5872fce5de6524914c524025da20d45b5eb4dd23b51f176e9fd42b00b0037d72770fb1610166389890e113bc4d1e99901692da05f3161e7103d70e3b4003481c75bcccf5405fd82c145bb668fd060316d09305622d90ca2086941c8cf00ba68f74cf1b0a4f38e96d94ba07840f42b95cdd3da85cf395188a6e1a07dcd0042ae78f5e4923fb5473dabcaba44a4b580fbe77c0b9d012e36a298bd6a3a720062f76d0f6a6687eb985751e0337ffde33b84b06ec7d45027e3160f82690c7100b330b46ca95465f7e409e5a2108666c134737b3db1f0f1d952ed0b0fbef05e00f458525112f8a65321c5c015d5a7ed0e63fd51f8ecc6b14c6262af6043d55100bdd1cb8e142ef3379f3b7749effb8ef673fdf59d730eb062e12e96d65f6e1c004172ad92e5139cea96d9b453bcf38e0f0428b77017e88e88614f518e8c7ce500a827ad889bcc14912bd0c94e9f20dca92747d9347642ebdec2979be2946db200bf6170e7cb7c8d897bf5de8123f1abeee5569560649a5e2b04b0cb2f6a0f9000bfa5cac2a2d860e1b0ba4cfd427b17f7fceb8064cc5d673ab42ed1f46546af003739f258411d848cb8a5d194efe8aacdb5da5c99b6da8acb7f346affd490c3007a45d12083425e4151ad13060777d8eeec438407bfcd100c1f66d0dfbd938c00cc8c64e39ce272cb6ba651135fb54a1bd9d1093e585b83df030e545d29507f005a44e802b80d6f611d1b403c74f42bc299145dce61b056ea95dccfdb44bfe5002fdc0b97a9a9484af8cbab83d3d798d53dc556bbe2a3b187493e853a35245d00c42ff6e6fd5d72a86fe3ccc44d96fcff85eb6b73c65915ec58e9c577eb966f00e78330ddecfcf30d53249308619e22afba0ede2ddf6ed8083b32672d380221006dac89cdcebe31440b76f20ce6796bd5c6627dd35c41ed38a460d12806e5da00665ee6d812a88b77b0ef89f2960da7ef10bca0d045176d57ff819f254d9b4900ba4dd134e3dbfecf932d8b6ac35d9f5965ac6c283546de0ac7e26c44fcbdf800e071ab6e986048878b077d0789721448467a6866fb9bf24188a3b4f0bb4c42008edf4ab450d3ff76269e8f6090c0adf5f4971b6bf943f32608b1f25c027f250080ce78b5b3768c804798a8dcca9d0b7c423a1d29a9a135e07e455532c83168001c03c849d093bd3e140bea7c177e84f0515409494bcd920ae83862fee7dc9800cdfcc95b9c2ac92632eac6177be3aec9b591c09907271730940efd081b009100d2eaeda7c8b659d788fe32abc16f953cecf97b096eb16c5bf1dcbe6821b8a0005ea92edf539a60b97560f0d439533a8c4d6a7752dc155985448d02a54b2071007bc53bd8760f9cdc172d22053724498ec83e3de881e3a3cdca00841f90259b009a451e7734d00484babf4941c40a20b9e593a9c3213a83037853206bc4ebdc00f9a3a7ed6ca032783bc7ddf8ce638aea1cfe615f0a1aeb661271aacdd1c849006ada26b954b80d2860ac6c791b3e71379b5aad63d86bb456001dc704f1339c00bd3370be22c2ab31dd3d7664c88f479e4a5c5ca289450e8fa24aeb1cfcc5a000de743f76f6c5d1584cc00d9159857d047327701c2bc6bf44f52a36545b1a7500e4f282816622b93b548c55f88e67cae4f9c49d4450361b600030d99d2c957e00c066891b9a150087e1f4bdc5c9c3fecc2692f1b914f7c384fb76917e1f8155000f59292a3ebf1f23e5906881d6d07867e1a035e3b8f47772679752a1f17432002785bffb56db1fd912f560526a0fbed9f780c89280827137155f8726aeb38200dc8a14ffc9e3488afff7d7de0e84e228f2b7b2b44b1cf6e3f6d206537abf490081701f06ec57d2e3555640597c13657da2a7d8929697b872e006f9d1e039dc002f576aa23c1f127b51e423e198aadb3907c1e30a24f74fd150a7f33af28b1900b911ae08e08506e1eb59fd9e96d4d8cb1877035054ff26570e651c9978612300ffc1d2fc2c028f0185fba7b31541c93551a8afd6d5cddd9bb9554ebc9051a100384d7075fb8b3575969f382d63536648a9eac2d9f3dafe6c77f92e9f0b457d006ae1681ccb19a2b8b68b312c623ba68d2a5f1a6d0dad8fd0c77aa45dc1db8200feae0a72560811fb3a87edf21dca54cf617ea86c7933dafcecadb90c22b389001fb3c8dc67ad24663ab17fa655be3343126d745569e08ea420c8c877deef92006f3988de8f9d80d3c3972f69dd5212d5958f9ca043714b99b93dd64721e3c800e43e0f06f2a69a2dadc8f8f4995a76bd5ba5403f32f0d0f126b1976d9001ab00e04411d26bfebe83d80d18db055356a5beeec5a0e39aa88fd205dcab63c4ee00ff700224d2f0c39febccacfb2a916d8a7ce21d99413568820259edd2ab1d4200344730bdbccce14066b421f85f7704bfce5e49726f03b9f110a8566810ca88006703fac7e3a371a600bfa6a9500f02cd4df053d6b77a3628eadf8350d4d885003cb0b98c41837096753bedc3594ee21dc721e927717330fc861b3babf8efb3005d66b760840036765742a63d136c3a424651de3456bdda7c5b2e301d8ce957006706c704857df9ea628f702cc46fd5a2a64617b760bd36db8a3d3fec27affc0040e080b531633ecb0f4ef0154932cea9118b563006a7d78c236348e90574980025c1b6b8b15a1d66ac0c924d95b127ebaf2089e1a7253f44b29eb4e95d3c5e00949aa41e615a0e3010b719b3c335dc6202a752b9e2796d06aa6cfb882d7776009e8abb909012d91a69aadc20fe5cb3a304181b92c64c8cdd3d9639047dd26e00aa665a1ee003ca4849f2eccaf987fc95aca99d686c7bf12ebc67daad778c6f002e6797214607380826f6dfc2b51ea36f78ea23c7676ef3bb9bff7ac562f607004b1ef52886ee9bf1befaa5c6036cb4e47b1b22253f9d682a306c4859e5d1be006a1ed95748d23ead1d39612898e5965032b2bdc356e00bc7e87f442125812500a687e3c92c2976440e86f797e7c5ff3463ca832979b7a1d74516c55c2b0c6400666c78e5e939329f25ff6e7e3d90e4cd08edf251f3b6b1104ff9d3374c3a7e00d914424cdd9e428373568d6d176f99d5d8df6a7797aa29e8a1558599429b48006c325170e2100728cf33cd46c054b9fc599d0aae7314fadd8d12c141e1239f00c701b567bf1306571e0a92a99dadf80daa50a8498a7511a4d924bb7a83418600c08fc68699c4f3cc8d636da425cee18aa3814cea9790210389f17598d9d76100f2af949380745ae7265ad9d628526bcece007cff9aea2e40173ced6dc7f63e002384e67ab6ff454efc8ea55a829f024b32898bb8213a2ded2b5a58eb2ebedc002f1f5729b0b1ee3904eca8890b32bbfaa1fc36b4beb0472bc2b393c42b2c500014cc932acf9321682e92e8d334ecaba92cd2bdef4a07f5227a4879e34f2a2600c7c2c6f8c73f9f4dbb48ebaa0bef86396efce39aed077468990a9fed2fa12600c2ef2f076ee7dff0a054425ada0fcc36b6389a5ba07e8afbf62381c6023e18008de67f59e58306ab748a6ce181bf5f0aed4ea5a430139f8862a251151bf3210070a16b08cabf2d08f5866fb365079370bda646a83bb71688fb83bad6efa98000118423bc38c885593e915920c4f025cc2cca9f3faa90cadbc668c3d5d002a800b2acc187c86080d8990fc19f7161b23ce34cacb6117fad3dc65795df117b1600547bb7fa7229eb7e87da79a487be7fdf7648bff7e4765f9f720cf9309a9d2b00f57334068f71b507c99618900585f4f3d0ff57dc11d34b23514922c9292473009e4e6e9cacd6f630031a15a90c13612b9e6137fa270536939014c211da3e88001fb90d48b5b2ceeaa733e6d6b1b266e1b91b132e25341a0d020f8f138c7494000ce0f1893d6f5b8b031c1f2a6e1b7e0a7c2a735cbd881fbdfd0d3edad1b95200cd5dba5492413dcca832ff34311bf4ab9c126eecc75cae24496f03020c4dfb008f62ab55a9b20cfb8164ae3a8d57d511852c8b972d2459303c16f33c8e01cc00d1ae6d0c8bcbeb64372e6b620915ec5ac4c923efdd807cbd22726d522f3b7e003fc64738f31bdd28b29d0a4bfebe5f43ecf3c81a9bad3b79b39c90b9d6647e00c8c840b26c0b9dea2e2f2407489e51a820a0d5f3c0a73ed4ef0a70b24db53700652f208a2fe0f4597e0017fc9269d78e1e787976b17f1729c1788f5b75cb97002d29f2ea824220980a723d860fc2b4837fa47d2f4189f3d3201da9e8802ebc00c53ecfe0c69b59bfebaeea9154f935ce5fb4ee40d6420d45ddb755fab2074d00688308a48275e258af25821606ef2cc12f71ff4ef58d2e7aea7f8a689e928200f45e0266957fd33f0820b249c7cf14c908793bb2d7161fad30b71a3f34265b00e10e1d6cfcaba487459d6b371e911635b457e385638063cc09b3729c9b5d52009ca026fd5203dc83522ba3e99f56727735d677b209b15b631b1267ea315e1300377a63d7b414a5fc69b5dcf6a5d3ecc4fc412d43013bd2260e10eec47d7338009775b62db9be77d7b771b24cfa3236b5f15f86754842c0bed9a28d8d046f23006ef9809a794be2f81a56077bcd887ed1d2f9b59e0cafb3b69555d5619582a1000cacb7ce15be4cffbe4149f796d61bf913209664a0e0cc0dbedd46bceae865006c960728aa8bb7491ca30cbe97616aa3e6c9730a841694afbfd645199608d800dccb8c3abb3bd22806a7d8885c6a1d7c893c314a2687d83cc27de581e608a300ed9d013e7e138063e9630457786d087c15791b0ec7f0701443b66e86abf16100fcf295fbe92b053d811a6695c0757fa5aa1c8f33ef42630f1496ccc2dfc10600bed501e6ecc40f9918bba90d6fc60532019a435530be257a5f6b64fec744fd00d0aed0f91651d598e870d6bf46057bedd4c702d102adc422c761f34b42ff78002db982cf30904b855ed1645cfec919f85c638389a4f416b48af8a765b512f2008a15af1d72df122889fe622675ec5285996135c8ff80bdb78d60ebf3db0f350024ff07ae23285f1e98a16cb2af0da029d21fefde6f9335856d650fc8a8f3e8003b841e4eb64d5ffb30246cfb5972b549ee6f991ef63539df2f4d3c166b074d004a192b643541e55b97afa4a8b60b86df0327471295f7708527855a87552391004f99ceedd2997e4c53c4a01fb2513f9805eb5ffa1300bd01ab4ec270afaa2b00d9e5885b6c924b02e073f98d0715312d671a10379737a346873945a428488100b8eb896fb0feb2e7bec4432d352de170336146940858c5838b659249b493ed00d9a01d91698d4b7b0e2ea69a997daa87606430905eb8e415b209157b2e3fe0004e3d11a609fc79029a64d146fe4b83c1fb8f02c73d75e84047f799879482cd001df17f03b3a5c1beebc3fad7d1e6f24558895a8e9c1b41ca3fd82aa970fdbc00d856050fb77392fb62ab27a580cd1f1defcdfbb03f2c8be35454c915ce107200e0b0b499d040b2895ec524e8cd535cf577bddbe634b57b702ecf3b5ae4b9dc00ebba7c3fb95dca8fb351cf567cdfcb733399ba2d96fecfce0c62c55bad5c6b008eae672aa865a51eaf64f59f86acc50641b73714088f7a6894b57d6058f6a4000243ce2fea334664c71ed1b3d89321bcdfb0c178be16019f3677b3625beacd00363835afc64c388b9836699c92ec4591f2f2a701e70c2b85aeea902f2939a2007771835fc4d0dbe2b5a6cfd40d93d0e1ce3a0f7083dc35aef07a56d452c15600388f7ec91c27ede5d40173fff27aa332b47d6fbce5cdb9469a00beab78afc7005346a0ff7fb7d0ffab01f037ae21941cd1680d622b8c7cebef7764ec7d9e8d0006ef2b7f076ab8d74b76b0b63954738062578aa244e9a7ad5a7bc092a8a42d003cf680a26c16f3ca3bd91a1d3a643c9a0e2976490538f79f1652b492be62810055cccad62c95ca83d77873d825a93dee6a3251ef3c979fc055d044723b641800dbd855ff7ed6790bfa54dde7a07fdf037e64f72032a920d043684b5a335291005a160da2136a2508c3f5dc73d250afdb6c822b79bba4477fcd130863e6787100f87616417346101ddea1865c64f0ebc7c0221359d4d4a3cfe27280ebc873a0001117a6dd890db39e3bc49698b925f8569b314c64bf5abed7e9945e97ac0ca700eeb4435f2bfe268725c0883e1a12ceefe4eaa7129c06aa5ba052d6f055c0790099d0144c608f4f0fa1fd702745cc29790ff508e1e973aee5620676d20089170060f3bd6ca75cb47f9b1df2438ff4f0329cd86cf18cc7d6a4721dd26fbf2cf0000a9d597fd0e23e607eacde8cb42d8be83351573eb1b0e679318f1f674db16400527697ac7e7891e2e8404e8dced70761f0c0ebddc2755bd676ac14037d874a0066bf2726380622b874e8e2caee3b7ed8d6eba8543145531f4fd4c74056302000ffd4875976089d513f63581aeec39c88a30695376e903775df88094d0bf18a002eb7027749e4f615786e461a4400607d26fbeb7c1be48d7804ae5fd4f6127d0078eb8932d153696a8b4baa910fda207629c7f91ac5016547255315117ecedc00a538ff07c4f222122ac24c52fe85492cee229ca925e93caa677110bea948c700407ce0ba8041ba5a91f88057176f24f46b086fb8cdd8e01dfc207f9f0027fc0030c4c0a3e22b43dcd85551156c5adc7411709b23e6877f260610259897e0b300b6ee1cb8566cbdbb318d37a3f652de5583bd799bac974290a86469e6c4f47d0097af5654c1c2c665bba3f1aa05fb556a890de1585b12bdb7228c9ff6f8c4f9001f96ad12d520581cfefd919d719d88e4743d58d3a6611d5365e4bfccfa9f9800c92f961edc3208841ae971641f24a9740945c0e8a2ecace2c0d06c335ba998000f16c49a923abe10a0d7bd7f08e89503d5f15d46694e0cb56ad624f8e13ed900d4db0ecd7061cbe7a631ac4be746b3a4e5513db1d0e986a64829fd143d38ca003cdecbe25f6324cf37e54f6ed8a7c2552db8c1c34fa08d9fa79daafe27d7b100c4a69ecdbd5e8253d6598d85830e66f75b753f721da55310b68c3f8cfaed67003284f11ba4b773bc3f5844469158fdbdff3f1010aae9b4670cb3097c0ac3fe009f40ecb528658284ef2c0dc883c7c1c39d87e0d7c56b082e118dad65e0c4be00085f0aa88bbc383b8e596233d793456b573e8d96fc621db7e21f404e98e6ae006e9bcba14fe090f16020f22947e0e67272fc9ca5d6223b15772d824358ebba00d88502b150a508f992646963ae9e2584daa9ebb72f0db3a514c312649b7b230061965603845ed9daa1186cf51e39df1776b29590fb225049cade327e08f4c100cc11788b02aff016b5832eea302bb7a57696cb451d108e65dedc269f4b194b00ac33e38c9e1605dbb9407dedf0eff7fb4caeab692bdb3cc48a7aaa591737f1001a3b6b516b0a4d1d04cf7ed3ada4aa9482269528a4ca241f93f47566bb572700a04c32563e269cda186bb0723de91c3091a843c351abe3a54137f2b41df595001c881f8916c84b91611ed8158c0a7d03c6965208ce2d6a713fca980119be5b007c0c30f517dd54f463c444dcf2102ac5b7ad3a3beda2263eb9a3853818fafd00b1c6757510fc5bdc3ba535a725dfbe730ac40cf96a26691e0f2948fc6526940079a3e57c730e6c7d1e4f06ef7f6a170378f2ef98752e7603a9ed223dcde85d00725a17e05f5d3351dbe9c76c4fe02113705f91de2a80c000045333970492aa00ede8cba47918a8f1d861a4f334a8da674c27c36b9bd27ca6a0c907aaafffcb00720d93169adedf47bd91b194cc452ae90199bc355244f350a23537c6a6a95e00ea112af39cad964ed8a0bef079a3f40c6984540b8a191860bdeaa09989b8a700ac569acc3666424e3718ac12056f7f1c7ebe6d2727d2b0211098357f3a60bc0078455807848d29ed804032bb02ae926ac994ef9646e54673b5d2fb93ee5a8c00ffeacca73dcb82594f539cc52a1127e8de3a0f1fb7fb40f8cab1804c071ec800e7e11ab3a821bb5e93b7433a6338c4fba478f07da22112a2941e097161e8d000d6ca28caaaabb794960f7d3ec812166424a3c16a7754dcd9d58cafcf941b480086b536a4f0ab0806a2b38ae6f11a47c3016cb01e52910d935e02ea50270cba0054d4a597e6069906ec01b6b677b33cc40fbc8d3cff1401831dcd6c0ab75c2c0058aa6bcb484f3bceb7654941dab7af6be540f179c29e9212e5e6c25c961f37006e47339928f670d77e037a8743977a14ebf780695aa6788f4610805f4d709f00031f0e94d985b2c46b768b48ebb28e12ac9b11c77c4c25da2a78718ec7f1930043bfc0f59c086757a3b5898f06d72a6b7d7ffee224eb5ba3d47b93814509700060b1b7e8c653006ff8cf20320bae40ea9a89b21a6d31e372e9cecfbcc9e24200644cc3b0c214cd6a1c8b31c06e86e3528e47ee24594413723e3d0b018e7e7e001c43f93a7489f149128576256071f437b0a0c7a61e2620441b9b7264e1a8bb003ea4029375463a2ed9e4bd63dedf7d76f63dd229fae0708a218380fed9a2dd00e6454dadef5dffb898b253c0ad8d8db074022d1d77dbf929fbc74edabb6fc600896dda8adfce8292ccad3198deb2916a9c54f17e8a818c9525f56ccfd4e01b0003fb3ec34641fcf002ed52c66f62e5f8dd78b5326c96985bfcf7ff622bb66600d10295d093b9b33a11475fb7a4944bdc1adba6112d6853e24df7b0ebef915700d8bf292d13ad91c6dd83bb3e1dfc9039bb29e3930e60e1eb90c9eed4a2079f0024cd75009d4c25ce5256d79e90876e664384b368df0615e053cc8e5cc1d4200070714ca9a1361e6c37ed261906803a30710f99b7f3cc50e6699b2cef7167c700b85d2980f3d0fdd492ee0519cdddb273ad51b04d610d23626c17a78f3671fa009c26494d4e75bbe6abbb480011c627551efd7a0bb459ccdf685d23c46f74f800b00ef63cd7f4f7117fd1364979772e79737bc5e379561b6e5c7cc62f78d1dc001a0329e0a40b32d3dbd94be89ec42fa5d240aa262310e8dc8ecad98c1f247500c4b0c68abf88285d5b5f8e0b40ded4f21002cf64f4a819bd92b4e24e71ac3300421dbd9d4f5a88edd54799256d6bdd3785e309763706d6cb4563bb4e4a7a11006126efd5760a6be2d9807f5c4601f1bea55e45f8001303b344962d7942647700a70c0ffa5ce359b404ec247b43fc1aea72f08bef06e35c7d67b130c19635a100496bda9638e9f65b19b6547686b7aadc5838fda7040d0b625d4c15e343606200db405b8123a1b200058bc95c8fb0225cecfb57dd39adb8a898a80d121982ba009537687be64255406925140a6454d193bbf9c16167aea7a3396466a30c745b00a0e0f2b4bdea944e38c96f9dab929c0f7a813431cda37a0c0a67fafb02a33e00e55a1e79c4b1a7d38119d18634eb32a2bc4053c5730093b681e5d55404b054004458885b20e29f8c304e1493874f4be42b3a3ea017e8c1b3ff481c22118d18000721b6ee2ccb9f133a23c85735086a5b7b4dfbe9c169d84a833ff56875956300ee6a7928c029d54f9145b5823522fa5522225e25d8867b00ce5fed73c198e000fe7fc7c71d4fc5bbad7e88812c6033162cfd84698b56b08e85c43481c4b9ed0068b53f79ce55ced311aebd207f3eda698c2ba71f69999d9d0bc003cc03880000381f7d522c5e05f3feb7f188c74c5656be992ea1f2c98b023b6e4842e9024e00d194697f72aaf536cceb6d8c5cd55c1bb67a0daa9a561fee541e88943a626f006847c319987a23e425eae53c62f225faa802ffcd210ff5a3c3aa10a982626c007710e6f81158dedbd41dfc96e16682497382e5c497113f84073adfbd06f7200071a4110ec37eea2307915a00ffb56e0f7e9441ecbe830b4e77a19217d38b3400419d53740765fc195c7a0c801a69d9138dac4dcb0bbc585939d4c3c567f48000bf7c4ac768fbc26937a357a1af8470e302e38c1c5ff836dd2a84b7b4734b230030e7523499aa74c32697cfd61f45260749265647b191d529d4082ecaf3328300e3eb3e086751bd2ea260df1d32c3251a6c24829f70d943c812e9b9454c106000b41873db9332b413402a65b95e65d626fce389dfdbc10991d8bcb3f801104a004d30be04ece71d9503a64869e234d6daccc16d520ee70fa07677a6fe70005400c12e597a89ea00cf8bb98b466f1ef060bbe043449221475d76b653f1abe3c2005e0ee243a41a5622a366d979af4d75e29c577675516988329ed3dd11dbe2b3005e4a0cff60d0bb7b39cdb10be9c1438b8e176063eb6fe69e6081f5ecb8f25b004ef35b9fda56730fb0785c6707e902d8796e2997b7a1a542a50f7dd3f7359600becad70b94b020deb40e965ed19a8c74c14ac90eb84df480a2c15e6716a30a00d27537f31ad3a6f5a3138c0b21e65eb053457e1677ac37829b83040ef7512900eab0fb622ada45136ae5bc0e3856a288d1601353cfb8d923ee175741079d4d00baab8bb39f26a1ba9525e7f2a5e4860732c98fd20b0ac38a31de5bb3ce23fa009728e1c2ebe772612db21d1019ec1d72a880328d729a2b4a324cc0f98fc6b100db12debd3b4a573bc317d76d8895d4d9df463da8505d9414935a7b8d67fd4400951efdc332865dc69cfff5acfffd00e72e2e169c36e0f4400e2b877cfec71a00b7bd96426c70ae20d93facf2f63aa54d79cd8cb20f04f7f8ac863aaadae4e7002d274f269e3f117a28afa8743c8ae1f1a0b0c3da28717207be52b9d278b482001d1fa12b175c241c7a3183b31c52385a85934e01f75c97be46ae293047a8060021869dfae9cf9647cffe884e5b9345491d5f810e34e1ee484071b9049fad0300e50a6ba2302787c918e97339d5ba78b2937818bf155ebac6b2fb5d068dd0aa000a247eca84db300f62928bfdacc7963fd44766ccb202c22dcd89530aa09c63002036d49046ffd5c6e17a66ff22daa94df0b149bfc917d56ae8542caaef8c3d00ac19c211965d15eacae35e12f09b17570e480f2d97ccf3b50389bd472bc4cb00e766d27f583eb85ed93bf029632614e674ca7ef887898ceda7fd72af5488b40064f59790d5600f60efd30b0159c844a9693f203e315b44f9f1ae9a15477c1c003a23e7ba519ff17c49ae74cfe3cdd8746b1fa921df770959319bad20afe00f00d3ecce56071de2f504f739fcbd239b36f11f3d2a7b87e40dd4936653ffbd4d0065c5c605ff372624dfb8087d1190fd95df1a101728c2801af7298ebd2d09b9007c65bcbe2415c3ab2e4afc7f7472c6fe35ada45e5dd696e4de16cd350e7c3b005f8c6c64485f9684aaeb2d5ebeb5f15f1a3807957f322d4aaab9785389707900e709ee6e2e8fe77aa5f64894e6fdddbdd4827f2c179e2548fa8e93847c1693006fcf68b24a90386b352cbd82147783446e6d4f718a05bc3e090f1ed92de7ca00241202a758b6c8746804c58717f8badc459bd4bf107ab18580c5e2109b3b4f0018f2030beeb657272552587317901d03ee5e90de4fd5fa01e30270d6454602004804d0f3f2eaa5f24ed6b24bdcdfd0ca717ff4ed06c0d9156069a06d6223a000868240c55a43832ca437543ba5779ec070ccf19f5b117d2f5f78ea89a6f6f2004551e0fb4312d1595c4a362be17434fb23c2cf4e491bcbc666f30a0e67e53e007020dfe10c8a1faa0ea661deddab19344197c3210ec06a383776df43410b8800a2ab6f492096e9a55a6475fe005e7c2ed834f77b876246bf15e13112089b7700840af4469f88dcbd999f36c19f2e4c946d8522c68e3df531d18f1dfe1ef2cb00e1c3878986f2618ea36ee0b176a7da619a9b464f54be8cccf10465f810644900718396bcb6e3bc94c056449ce1238e35edff6c20b3118d6c76d342787bdbd700abbe926aff8b968d77a06e73b7962a55824c9a2e501bb8580e5b788030d97500199ed467bec0ff06fc0ae980875269a8e4189b24363eb650c56da5305cc661002ffda40ac75e6acfa375eea5e8566b656cf0a3e71e1bb602a72900f548bf4e00efc594698f0b7464397a08cc5e054db7256192e6a8d063ce6914d6d43f3e26003dac7c7cfb25d24aebd988a161c3a424969f6a175cd921cc62d25ab5b5dc0900443c71afc2ea27825611737403ea4589494221996f7a7def5e12ed0d26e9db00c5084bd4d09ae051dde2c8e7d81cd5ed36d000f724226cc1b72232bcf1fc1f00d4f29bb3be600708432ba63c84328a543e143c556a76d6e29ec83f6d3360bd000a603583c0856b370a9b5dd0bd6bed07c701db04812cd3413691aba1d0e80400df0dc981b937ef205d21932a4a52e2587278d447f6e1285ac21752fc82a204001d929bae77fb20a82dee53d2596dcc626948f3a7f1cbcceac47c1ca9dfa87c0049676a37122b81143520f2ff0334942470d5132dfcad11ae5c5a0de272ccc000b783cf69e2b00523f3565950e69a90ae8c6bab854be5edfe2e80c5a2a0712d002ca700f41c66cc152857186196f70195d71ee5c5acf55f8b2271cf348b4a8200c6adc11bd964e52d6226aff543c20d66e6adaa232ab80a116b99950cea610600fceab7252095d25209b606075417f5e4e09231d046da9bb738fbae5e7988d200c564ff594cb8e2ccd5655c2b1972c5b8ce79a23dde35a98ca38fdd37545227005c1dedef9814d88e3472cc72671dd6f0470e16438d95d5a32d2865a0f474a50092f11e9e06610874ac574e25743913c85ee3f49b9c447feee39fcebc1935b200774b22a2f6bbec6767ca9d5860428e278b8dfba8b1cae75a191459d8eac82c003364567878ec613e2a97f0ddddcc8c50346518a82a80d819aa0fca015e7b47003f76a2a6269e61461de82742d3edede771157ee9d064d52f7fbad8c5bf0c1b004a8a7dad5892db609b27958fc9bb72722334e684d931b7f2b5dc72e496cab300da33c812642ebaad3cc1ae6afc165ae50921162d4a3a10f1b9f19791e3b331003bc812cb27b3f7a3a6f661d18c3c70ab8d73a0a368ca0497574285e945e9f400babf130c3380aba6f022b8e452c01e5c1a2179336584a3fcaaeb6af4ace182006644c8ea595ba999392ea2dc346ec01e97034677ba8ce6509793d3c0f30daa003b5f49ba0d6448d17e056522e5c1b5a3772bab7915deb498d5dbddded5f86000c48e8725f5d6292261ec6e4ce6f592f00e1034a65ecc8dd16cd8f85bb462d0009012fde946a527b9f04863baad9fa5821168cb8f2ae3bcfbc619b2dbbac2ec00cc757fa9c1856600d19940ff9ffd3684d695419036324ca6492c202fdceefd00938e609408130b0b907ff29a920505fe4abb4d97a1988ec92ae15af976aca700e1df8aaaecd7e6a79f30e1e4027e0e9bb2d3d7f220bf1be466bddd4a5225c800f58511190340ddac2142dcf41d3243354310f05c0de0980444549721f22c700054fed6169ef68c22d07ccbbabe972f0d4c59545856ba4750b3ea4819b90ce4003c442e77d9395c0f1832be33a77ca42d82944195b3bf0174acd982750ac0da00ccb1805184d1636169ea698d36b7b72980a1a63e23092c5c324c93734efed100dcea76617d8c3f6a6d074f7b4681f4a10ef4948ff9cafa630c95f3077b2e0a00962502a16d3add80ae8157905ef4cbbe41359a29f043dd854d84914cf303e400a230343dc3f74c49b219b9d4ed085db62798fe3b9aa7d2a67ce0c06323687000042543a1326010f02ac8293eb803c5e256371caec319fedef126c8c21977ab00e94c7f11da52111082c1300ce85320d03678e6e98abdd0a7ab0821b73dd5970081bf297008440dedb9a9a0f898f589f3e2bb17848c575270ce85c75c731b2200b1a318e782c61fb08e4545f57fcb181836143640d70b567c62908d96c01ea900c1027bad2ef706a0fe60779f8ec597e52374fb53792eacc31f0da3334f069f00d0a5a86da35e6654d4842a4f01c8ec553b3d370ebd98db4364f6165a2f5b3d001229221b4ccde04208b73b818712b1ffd93c8445577fbd79514a123990ec3300ac56e75f3008b9dd71c3e69513ab1fcb3c01a14140c61fccb3d51ede0b46bc00241c9f0991d87db8764f9135dbb50e2742f3bd9eeeb16f4af4d6e30b99a14d00cdcc288bc9f8a8dd2bae2575954a2a2394a2480ced2144bbdf302daaebee05004aa9fb8fff82be4ff359b8a595cf0affc90300d979a1d96170a1ccd2f0cfb2000f3923bf688d6d2ddf6317d9b2f3e68ef35724252b7efbedfdd4586264ed91007b42d9f398471913f43408225f9b15a2512c49d4c8ef4bb50943dfc8726e0400b48a711d4d709ae91d951fff63c93dafa544d2bd1afb07a820e6ecb309572c00e229de36dec4c6e8bafc256f145757d0a4d915fc15e4ea8d19b46e069c05ab0036714073068a7f1138231e7d570bd1729eda9df6bec471785b9bea48ceacee008e0ff30dc7ed0505f45ced29bfce96637d641f6e25cb1abf2e2acfcc41cddf003ee8fe15d69d82de61c0b67328295d37a645037e1cdf4c6656f9278c1bdb4d00ea68aa1eb2c1013d068d641c4b310bfd4ead9dfb7c2cc37c7876631f4b2700008af65173c8e4d04ea7334580e45f4f7b107991965c37753a488881e6f8688f00ef2a8790e36f24ef7ba238cdb669cd3702235b2b33ceb9191b6170500700c6004697eeebd71294e45c855d842de3d3d19c47bf22920c8be7db66d19aa4b82e00902a829e015a384dfb903dcddce6150a5f406b4ba7d3583cf9dc57f32218b800714a83bb9260e976020ac6841aff9bb8f773a925095644347d370fee639dfd008341bd4d1ddb3dae003eb8f558deb5524767a51680431611056fe57ee2a9bd0037dfb476e929024e0a1213881bed894aa6a53a0fd2a08b372044fd89c439760089deb0261481e1b37b110c3033021d9b8e16cee9e8b79e48d714c5422240fe00a20e18ca8a4cd3dc9f04a74ad91256288cac485b3511db486a5a508e6ce04800b3eeae188a438b6f0397e4d1c2295a7e3cab3b5c0ec207c010e21ab43f89d8002ea20f81954f9e8b2e88f4db2a8826eb8bfb485ee72e37f5829a8a1d50563800fe541a5680a0fef03a79a6fba835dea98b166172848a2f4db933135374f61d001ca54f51d21ac6c6a4070a5ac9accacd2517d4decca895fc0f57a4228f4c9f009f368895f79734b9fadb679d4412f6399ce80e033e74f8d8f0355f229b67a500c5bc3a5add3a3b2d14cc0359472ac68181b8583ba91d575ab21010f79aa9420052035c27adbdbed75cf2575a50d83bc90d559d7f65e2edb23e8b4620dd00fd0074fb57328dbc16c70a39a905d1911ea3984652d0e84e7ad7f740a17d4154e700d1adea2c35570a7ca8e3824f3b0e05df637ca823a4daac7a1a55e1152975f5000618d20854b184cb6b1ad322b206f9d3b97f45031b1fcadcf0e381c026518900864e154eb70cf598fd9e643f5c2c04bc2a3254bf82fcb701eba4587744e81d005ee737fa6a615ec3ada5d76e05392b7b0d41ccaf1a100b65e6768f78520e21000668b387e90fd2844431249b9b228c0ac6f6947d253bd1cac2664d0022435800c6ab5acad7630126c59652bf2bce61fd278d8880dd6249c9d58d17615e5b72000182143231932069e805be87e144efeccea4f08180e870a46653c435396be100b3acf9fccec21f93aea9e76f47632a5572880877e9586f6c9c95dd1d786f0e00e878e2f399e7dcf9e04b2335e779974c69676c5d6ff64a0a1076a9c4d8b6570050962f88d389aea78b0893579b444216dbdf92bde40a6022838c707f3da5a7002d572af871d60755b76cdebb949a982b7ac115b5ded5d6866b2eb50485d8cc00c97edefac92c289fbe609b883665ef7c37cf14d31af49bbd99c9a3f868d1770053a1453fdc86e5a57cc59923606d6a9dbee8861673b7339cec5dbbb470fb41004a2e0350c5fc838b0d51745bdd861e9ea5bd694c48a820bfc9d523233bb1ed00c1d693590a350efe5d1e3e357347b1e23083fcf11e35eb502563cf4e1b8441004d4dc142ffcfa8bab708db63ea6ead859c646d736df85a85d459eaf9b2921a00711533712cb54f19603be6c01f209fd9a7186a7b823d9c1f568a5bfcdbfd9f00ae696fc4c185bdb1e66ba794ae9ec92f6e4535f3af0a7a22a49cca14aca7bc009a71546c796a33b1c47233f417f4984c42717007dcbad416f9e4f81f41fd30007d73a6df0347b73de656a537c604b6fa200fa99e6c5d4278e3ab843e9bf33100f659f97c3bfec3ba954779e77f9e1471c285a5af6825b1e880fa35a89a0872003eb7dff85d660b536f206ce8b6b80a0d6cadcfe782f2264112d51852665c4d00cbc2dc5b9c35a62c18264c6d2d135f987e5284aab291f824ba3d54526981660067fdef3ce8af52c43a699f3eed73883df25ddeb82257bf775f044deecb9f1f0059d11af8ba4a55403b50a78435ac70f0bcf691037b43af0bfacb2e8aad44df00e32d5ed979579393bfa45ea535dec1280ddca061e9f2430739c838290e65ed001747c6ba20f7eb820e533962f70cd9ce6e950c3cf7312fb573a1c0edecd9d4002bab4ce767a08745dd90595e99e33706a54fa7df57c2c78bf51edf7574c9b8003ab16ed1817a22d1cf69612dc9b36cc4c00647932e2f1d7a799458444cf52700b6fdcb679101f31bdf58dd2ff2c7bc3c99f0a667d1e0b5df8a489272a3bd0800c99493c2344ebae8a3d0a63d7e2bea1699073b8cb25cd842281d3aee819f7f00c9840dc90461b6c4392b6033c2efec44968c0c516707ed30df09c9acf619af000b52f427d1913ddf26f1032e92856f64a66cfb8406eaa87b6f427b8e7ee1e8006a74be167cc0b70140640a510deb3358f137d2f51058a0f74aff60fe908e990006beef434d88bb252c1e77f3adcf4e7da365be08248da3e03b55655b5580b40079a1ca5f88a277c1341d769e7ce0cb12b33693e23c8e6b19656c2971e337eb00eede0cb046e9c6f4204adefa25df793e964745ad8f19ae2a99e81404595de900baf3fc427ba83ba4b03b3018c892af9e25e1ceaf767bf655f0dc0484f82da10076ff8abbbcc78ee07a7eee0aa9f66955c4e360cf287abfc2233086468c82f4007f8b4554a6656a7640d89b4a2cd0bea32b76f32b17685dd56da76cef3f53d90051443354ac5465d8ff25cadf7c49ac8ffade622ace2566e7cc975a67d397a2008e10a04d5309863cda1bec4e8ccdf5acf4a2b506a10b852dbbd69df83ac75d00367a57bfcaf01cf9e087bbee19b1fe625343d42d6cf139bad834591e8ebf910005593693b30fbeb28f1e5ae099c5367d2fa07676821b0e98ffc207e8bc044100f98011a47b44e156ba0c5f510e08049d7c8b9dab0c00e85b06fb1005951aec00441e9460d62526a388933f0e3170c06dd8ceb296629748209b8a8f9c51edf100c88bfa9a97d27c48aa1a234904eacd51856ca4a39c3b8c3f6189ad40d9c49b00add8fa53ef0a98a62d736bb313f8e9c67f6567805f1648a1b919493011a2df00f53680eea026624b4ea9d252a3d6451894b8770e5786def8ae848249de2dfe009dfe707648b1b81638e9aae20bd55eebff5c55d27d6f9cb1fbec5667d8822e00c4cdf72e0a7af61ad10027474b92cd8f0a7b52889f7bc1c2ba2e38625a0494003825b186a59d0f0c4c6093fd4bc152d92841fbff45357e2bfaeee51712a3720053a2e7c34707d4e38850f664538b00097f35a2df23a483fd66863e0dffb2b500b2442564e2a2ebd966c46d3d44c1fa8bfb8b496344cc89c847cccda13d022b00297700e92c9f0ea0e3116b83f5f6aebc23228c729b72ce8ca282d5c3c7c35900e0eee9beb07b88fa67faddc9978674523817af1f9afbed5318192ec350c9d800f7f801672c34e193f76c086ae736137d8c81d63d1543101c94604d9f49a45c007ae3829720c2edb7a981e71642faaa4b037b2ff398318b1e85a636db55c27000fea67b17d13ca0f5d3e85bbf4a073fdd1f4e267a88dc3c6b7da97f968b3ac500a4e3fb02ca9ee48d94ed03f79df8aa76a4c2f5c95073b42c5319e006656a2a00b55127882886e8b0a87269d4fe70be00f41b63a546a7b8cf1bf224efe4df1500e2c4179298672f302ad79862bc902e80b31c983aa99c69b0eef18febdd9fcd00c42d3b0e1b43a0acf3a1c01bfc3c76df6b95d3e3b1ac8a08cda894fec0fad800fa2151578addfc2e6320f58dd177dfb5977beb20193359f5a6eb8a1be95462000544d9054f4ae2211191543a6aeade0c37457e7ae3ce5981b72041ceadd62d00e5e9235ba7b18abf8c195c764276ae94f56381ddaba5ad6e0efad4437c093400754596f19d50716aefc63cd8a64caa09606b61e361c9d4f390731be2a5a165004114f873b53fb3768a969eec229afc5b3b51ea56068b954a7c388ab32002c1002f1360246be48fc56fba988aa536e48aeed9b54c3445b029c1376de046f19b00664022e412a75c797ee5ba7102b3ff8b7fecabb5d56e339b51ea86e60bd19300820719154201f521b237f894637f8e9a48dca44e10716e906435130066ba82001f55046fbd17fa9ea49b09b63cc9ed23bd4c89f4616c5b27764b409dcb2a5500bd8734ba630c5f928c57934ca6e83334def7024f40bf6edbc25c757cd6adb20083e5f0c295ff9e19f58048b4179e6ecc9bbb12c589119e47016e52dee1a94700f94efc018797b4b708cf4093a343b380fd8b27760417ebe5cca2b062e2b8c9002d65abf0c5be8a86a8d7777a221910af1d93ddd7fc3156b677b7bc8e2531ad0080b456d4e65c1929bcd4ad597b0fda7e170c1481cf839dc17f463c3b0a8f7000212753deda27547dfba3e72b3c1dcee0a5d8e3d3940e10c2ebd91490da46d30049a2ce0f67cc230bd730aa553efc285362b68c995efa27db842de2c56814d200cd1362b3b2b35efc1fbee2a37e6db436f88e857189e0fc05f660266fd7e4a000b6ead8b2d878451d628804dd48f1701b48dee713d51618d8ad952355f61c15005b75e8f2425a6108116f0529eb612259db3b48d39c16f60c207af3b109f14f006a141b21b405cc32514716b700480c41f3a76902fd3b3e5e406d7991d660eb00f0850a47c39f30e781e742b8d20a37b345b6bfbbe2b8abeff8f4eabebd11d40079bcc2be9996e8985f86f9bf0108bea420cbaedc7ac9bd00946a1522510d7100508ce5c294b3462fce47e25d269896f115191ee133ec8a7a88f7e9100650c000a03f338d98d9cc166934bb14357c8d7519458cedbf012c125cf60123f1a09e00652ef87fd28d85191d6ddeb8261eda74a97f221a7692f3885d6972018a932300b891600dcbf3a18a7fee90f1d2a230bbb1a1388f436319f761ceff2cc5d5cc0031e3d4b1d044a348a81fa4c20bfa8cc4ba9c3d4c93db0eee61b3ef7bd71158000dc69d53a5796d18004c570d7aae6a195b11f452995676a2b27e764b1529c400d470ffc4b6f3bf3be07fe5a5bd0673e71166335c39028f594319e1831169f700d8ae9727e9f8954aba2f0ca678fd20ca5078755ff446b229a459e8f23c8b7e0032e49389ef7a18f994d3d4216bc28e1a35cda4297236378bafe7dbb871ad39007022711ba038a8f71367ece46d059bcffcb87f90addbce6e4fb2433816e30c0079bb297fd82a107233bd34222921ca0a466308b78c5560866d89bffc73cc4700e6e1280610cec7979cec678094110498425dd3da8b7c9b84f6bc9ae6bd096500af8248a9472c8571231aa1633070db1846dfd5bd773c86d2ee9631436028210023d6680796a4f440718ac113532391ab6abdfe686e2a7d75f7d9f6c7f147e900711e83bd9722d45d72858e0bbe8244cd5f293abb86165c260c470f1754170e009effaa15c758b34e7562289296094cb9ad33312122f245055555ac9334e7b200eb402f05a2418950291ea6cfb45c297dbbe818cad5478dbff731e4c70cdbb100551f51514e0c1c3093e2923e5313e43be536ddb386d3bc3a3744e39ead8cf400944e8753ca67d3dfb9ae9c23aa1f1004fb47f61efb0159cb6e76b19a8551ef005ba7beb7ac1399e721960c17119827bf63b340741512b76a742542ad675ff200a4047c777d03ef953483bf935b6d3ae17e5794901eb1207f46609ee8ec640a004da1b46d074a71ec5194c57dccb820d89b3727ac88ff7495fc1664509356c600636775d5b4f39b13fa98d84736a5ad5aeef3b62de08e83fe7f8085f3b5bb77009838db2acf9ff47bcbe63ae0a916564bee6beb51381c21bea4fb047944736e009b643d797bbdd562f1af4b85e9d6c13f37470ccfc355b5e36c8fee699e4f520034d140c934c8eca1528fd840bd8e16e1cb60d81e418a299e5de58d9e1494c300608a013b0562d41440475411e92c692c2b1b8caa0ab9632404f085254e712c00f688a23bb2290e5752325ad6d4ccd1ca23f384d28c493c304143d14464b49b0035c0e9d11defadd041b52c0aae0a60a0b81067a8dc1a032d39518f8bc4bffd001ddcca513539b615181bff8542e5c7f9ab47855065de88df9a9db4b136446500589b3ea1b89ad4c6dc21a6341ecfb5438ad060a88cb76dabb42e17f37b0e5900715395548654419df59f82004d68d42ed0b97e3838048f2caa0b674140c11d0052536c0a71cbe4dfb81156bd5ef2defa16c43fb425c22c563fe7a8003af24300402c67b67434c6c28b6d660e14e41ebcea10271cea5970263d3bd069a94a5100d28542b3dead8c66e007a4f2476aa66012f960a2c246516bed3989edd0b3aa0076ad27428fdd9d17ab49157c820c20f42c7ea74dd351cc35ca258d42ea6b3e00163292b6d60a9639e99053433b139aaba9196e2358378df96bf85a2e942c8500f10d102cc2e562794bab0308157c2fd66358b80dc096ab6b4111b030dc730100e07d96b0730e65e88afb4541a63787e602ea8af63803757c3fadd3fcf3008600f6a37221c222016ca4caea7fbdfa2f5ab844bf3e2a3a84d729bb851e4cbb8300ee8605edf018bb7842ba63514ab440f298da06bfb32447404602535322db6500b90fca233cbf2ed2665df9068d96d743d2894fb8cc73c4f76b0168a36da7b60009e485f34c725d5d143ca9a828f13bce7996273a6daa15d1439fdb9adacb18006f87e69e29d2dab17a4efd0321a7158b383f652f095d741f5abf98642174a200ac2b4d6bc14e3407ecb73d2639eca6a67bdfdec867b71b586aa7023f558dce0074dab43aa6cdc975506ec7b7f27b48e0050854b9bad280e8635caec1ad25a800978797d823c8cd591ed44579227b6c305e1cb8d28654b4bdac4c4284a5d04f0011c92ca873b8dbc1b3f5430ea953226f02404354e0d9f01bab291b2225ebcd007e1a0cb2b6d321cde3cbce3db1e732f7c12f819d8bab52ed921c68d71230e20092efc3b168db7fddb48794abe1b31c1da3e6f48b81d10e3544a57b94104083008602377989a11d56474a1173b859e536788b9897c23c18fd6b933c48597fa40076c26808df22f1702c6c36b715ed4cefac76dc0efaaef269215bd57eb9af8f00bb85731141107fae7fe7af3c6ed2fd256cd4bf52b145f69f8b618bfdeb87c1006316228dbb3a09a49fa83c8e0a3cc55422ca82cf440631f35aa83b983d25c6009f6360283fca1a0a2e488ce48ea16b44c7b40201fc5063c9359ba11c47537a0016eb61753fa6350d9f55afc1f58f0b246923a489300b20aa7a447101f8aae100b9942c7e8261c68c17a6c2a9541201796f31b0f3f863e6c02e1c69c0ad5b7700e5eb79da1bee81e08dee0cf603182c996867e97b1a205cd162f19c662ec405001969440093fd990d75ef7cfda3b632add6deaaad0d090efa8889d9ddec11ce00f46ef8394eef1d6450ec1b0fc0b258ee8f0e1a4fde27449fd55fa3db60a36c00d9055f4ffc8c423eadedc327d0edfbba0ea041f8d68d868d7a0b13be1905de00eb5e2ae3230e49ad5cd1caa33d1f771a583269a435ea45b6de9bf38309c06600c73fb3cf216bb7e3c5f8ff5f071de7f7ddfb395602a2c97b988d3d96d0b9d300bd22a90eb0bd788753153bc9ffe3a09f50500897d1aeb4319a1ecf86e5ff1e005f7057c2841ab2b1845317a7189e596a44538ffeeb37220819e937ede2815300513bb921ac9e982f084cffec4f45f7111ee40496bb72b67966dce7974a9509007a16c89f54b874c3e957e71d51947149456a867efd7df4f6fc468f86d4b5eb004e4a24e869d68097d8ca94b871c703b673d698e4445dc644dac7ce7ae887bb00a87c86fa1e0ef30855e6926ed0fc7f3c9d6d9e10b11aab2be731311c846c1800e2c537157ccc017cc714bc72286ee3e783e244a3f31044dbf2167c272f8d5c006b8173c3f528742155f684731babeda1c8662fbe99949272d2ecbc5df06416003421c9d5127854918f6780feab0b307b18271c355d5397110a83000a01facc001b30462052f6ffc0346acb8be1ec7bb8ecb6b451025d6d65d738d04b7aeda400419e2539581aaa283a6f2e7f86903b1ec802853849dbf56ebaedde38fd2cf200885e081405beaad9b1073d647de8c26bda05ead968dc20503442527a60735b006bf2f781e6caeb17ed7f5915ff8f1f6c58093096f74538b9de86bb43d8d69d002c9581906d44ad845efb610423c6bd654124e0766757367321d642d9aa807800dce8e7e77e46414ad3ad64cc5fbcb7319f2d8b770b306cb45eb2925586ec890031aeb01c51d01c20c81e0a10dba2ddc4b69e31299ac02c86e70f0027e40e6900c1701dcedb4706cb948c73a94623fb707d58053492712c1b5fa1b4fbc36500001793b2232cf3050eedeb43d977868bcf5933bd19de31fea79725ce22b323b600eb5768ed4c8c033b34c95105c2a51d03bc07824adb1d9c870b4a25db7b299d00ff2f59cdffddbcf15a2637f2c0bf959e1eecd8d9c9c1d985d4560e72c22b0600eed1ea8a81a6aa475a2e3b987769224a1214c750a580728044eab092c4ee6200ad4d8d68b9fd27bd8c7fcbdc3d8e9ee0ff7e89bceab1df75acffdf13a4d6080018422667e0e74355ef331f3a562851d12657283a919bae2e1845d49416df7a001dc8e1a9e530e4018333cf574df6215f00420429b4d09dbc9d4a2d341b78c700be920ef32374f9ef21cd0d997360fec277384c42814d8ea97fd8e8cb21b96600f0c5f510116c3364189c73ab7a95eea1621867908996ba0509d8b67381f6ce0078ff2802a39c787388e4a6f2a28fe51e7258557f8994ed9dfcb5d8148d5e2800a3c412db2d349681d5d13bbed1ca182d778cd0d707cb49f0659b6d9c9a2b9b00fd9cd12072f5be511ed5eb8fb983b73f0382d4c22cb199ae3871f76074422a006008a0259043631a62926adeaf2bf3b0c6de61717d263659e676cfcba60ca700f763e30b127291d62cad328b53d79e4cc136c79733d03fadf160e133b0316500b42ab275f73f43e0d561fc0095d39e8cb099ad5ba006e6d01a9fd21c1895a400ae544787768a5760e51805346cb0e93361ddd9d7e74e989ba64bb73039b33b00f9850c071662059f993a451e42ac4f9f49eefd5e903c85a0668a73b43bd5ab007bbfbb7a41a2db0e6c09b3513c462235b6b10236df67b2aef6d3b83d74aad400e66c0a457c24f7d0a7221ff681abcc1e3428d45babd3dbaefec99ee726491e0094cb30c62a392351fe1bcf41295f6ee65cef16105a1ac0e6f74e095a107c0100bb7ceaa6eae07251e13ac9f79bd2037b7b0545dfbfd34dfe2fc33a79642bab00bd6dbb2b0ed6963aada906b0c66af2aafedd93f1553cb4d297499c190b3e6800aaee8d5cffc54678054bd9e285f584cb136a5153bff69f246cba07ce34d5ab005a39bf059f378263825d2fa5ba5509217af96a6079140e82abbcc21f16b5bd00c095b5cb518aece91e68a5dd21db43fcde54f70f29ca15590cbf15b8b8828b00ca9fc27ea0988edeb82144eabce5f5301ac0056bf55d35aac7001e6d1df13e005d91e1b010dfa7cf024f8241eca41c1388f7bbacc585e0271479158e8029110036cca3adca3c9e5948f8914109ab1c499929cd2212f2437b8b7f6dbd789b3f00844b8039a5c95ab625cb35ccdaf3e656cc7c672343ae16c53cc8127833b76c0012dcc188644ce2c3c20b063d55a01e816a7b8c5694f49e44d4aeba3c7469e0009ee9e2078c5426e93d14cae9415ab23c431fe303f0d1831bb5ac0f60246802003d780fb066cb0f30e7e46e8f4722e1b6811df389d761674f2d657a56d6e16800f3b156505c0f38e72b52d8cfa078b95ef1ba71108a7a37f4cdc4d6974165820029b7edbbfc7695fc1b6e2ad1c616be239db331621496bd24cdee9c27c0fc9700d2ea349d6b134701cafefcaf1df80d1a30b7fb179a3aedb2957de67e603dec00237fd9c9194c808d58ac4f278f4c8d2722557a31b110138e61232bfcbfdc58001fc6137db54212aceb6805d549b6e4c03a859a9d9db41c24013b7b7160f142007ab2a656eb07c3f5e903ad0ad014e7c43227bad42ed93b96199c901157b2e400d32fa979d87202049d6d70c672e784ac0246872afda31a49304453b7bb526f005e8c2bb58d9bf9679e1ed1c81f352b4fab355b1b64975043b4f7d050bccd5f0053c52fbc431ee830afc8ee8fa2d2e11598b82cc507a24d34269ededc1c17af0022c9aa64fa6fa87a2da54c7b476e2e580678be6e31763a7a72433c82577fc700de095c9c002463e04c907f0e9032e7171bf8abe5b1ef4c230f49b013efcdf100b7d07e20b168fd39fe088902b2baf3925f618a17b15fbf6c76e1f02c26087700ccfe3a6a35209bffc04e50d163b65d62937c80e79ed36d045fdceb12514811005a37d836e4e1a307158c26951ea927acea05330174903e44b374e6a1990bf2005122df82c111cc62d4cb4723607678d78418fb84eb8acd4d389484fa6543ed0067c29ae6b2278c7e9b714b9a8c64d9545e99174612debf9fa7d00f2ccb7d5d00bb1c6c22b50c9631d8dbb0c480c17d13b81ec6e942fab4e9f3ccb6898ce32a00266473877c286053b13cb43c17d8728020843f02874b01dfcd6b7c1e55d78f00a8b3901cdb774e23ccc0e83f620b835c5bac98d38ebffc55584e5b593eade8005c42168f376f51e7836076d9c75a98f7ab533defbefba2754365423219e5aa00f762aa5b4fabc92b6caf0691255c0e8875b9c3b1489383382920eabb3a43ca00516c52524569a6b92eabc2f5f37d56389d7152092102f3285c612ddee3e65200f0ed2ee0ff84339f67a75f9f75597fe19aff0bab067db687295c24ab43b72e0062ddc0ed39a85285b8c5cbe154bc776164d6646c519c02194426cc40338a140087869a33f9cb4a5954dde732884cb79e6de0029f2f49cf4a2a19aa8df9b6d600c0a12119a387313eb71c735c13adac1aff0fcdb135c2d520b34f552a55ce7200665bd18a8bda23199a236e187727a9b8237982fe7561f12e2d4fa440dda66300bfb79b83d6e8542f3cf6856ab1dea8299855642ad4712239c2ca7faa87542e0046a3d2863f427e317fe9d17300c0c338a36ff4f85c401659c7cdc74ff4c20400256c1f6d751059d2212bb3e6b0fe1950a34263e1436934024d77f294feb88a00c5a394e8a2ec013cba82aa55725b21cc027bd84d6b38c29df32d8b6f03c932001dbfb5ed26a6874028a450cd2e16546ee0f35618078d31feaeebf0caf22a8e0025c98b00b89e18b70218e6b5b64db048364fb4e1232dedc17929e7655bdb96009882090b65dfff8f3186d13925faf1859de204c6d5534ce9439ec86bc5ccc100695b249ba165d36244f6c11ab2c2fd0012315f320c1a16651515655b4c78f80086fa51bc7833ebec492c3fe04bf6b32ab4c1aee16dd16a1b9f93db80a4120000c1ef998fe9a3fc69055f186e4b71d8c82d580a22841a2064e29a541491bbf500d111dd5ad4b890dc146c0dfa02ac038946ec852aa13f08a8485a5d7a69183a00583797fa3803ecb6b40fc521ace11b067913a2957f0b6ae8b5a8d419d94e1c00a8d90e419f17593c0ba83baaef28f95c6e381e1f6ea8f4b0631a5d171da53700e10d6f9e738e5769a9a010dd53dda18d7dd2b398bf79cb05ed584de58ce5ce00ad3f83a307b0863f001883277ea45fe5352ede4be383eeab7608f19da275bf0042279829e88f0cbafdfd26828779eefca50d418ef1891d88997af57bc5081100dbc3f465163c85923327ebf4af8aeba8b8b053858f18d14caa2640d8957230007db763ff866c15a0596fa608cb88c3f010a9f432dfb4854b7ca9d4dcbedc8d00ffc623eacd1112d01e7ae5dc3f9676e0e56d5cfbe297302631fdbbf499140000cb5fa52f5c817c765ff74dc4f38419a57630ddfb6aae4c8ae64dd4df950e12003c0ac4bac565d544501d725b3678e8e07d9c13864d8f942201e2aeea23184700d7518100a47edacbb3709347f66b40f4d11fa906b326dda4ebbbf3550d64d700e8f0ef5f8c610cfaccf28a7984dfaf6d55070d00f87df51bdf52363681073e009f4eaab09cc68cf3bac570e8903ccdb0bc669b2e7f58fabbec118ffa82057500b9af549671fed1504cf8717f28e789264cd1c05ec2b1fbe09ba235484883d8004e93217d18f085137b5f394893d95da9467a0c5130aaa9e71f20a40955679b0061f4419912e63a97331b2c7f9f815c796d504d0e8a51956cd882e4daa3ec9700e4d85f272bbfdae0c3ca1848cb737fc0e29a3310f08e683fc1fc060a61b2b500e4c29803b0b3e0101c6710227093f18ffccb6121616e0e8b99b93df9b3191c0070a1a273c32445c3c37933889e821250f3769da8085479f892e6b1b9af474100f48726e2d8afa43487c8603bff9c125e0ef293cc891072babf7c3e0603edf2004b0738af32bc1a300c2471b08e899959de70b7911c5743c08204545189ae7500139ad755bd940a0fc9fdcfd80ddc1d206da2ea78babf64ed1298dff68cea2c00fa0227ca5797f472967b7c446dc2b3ba0c0ee9b446ef2a93368d9b53fee68b00cbc6a81397071f0f4d9b4f88f85c28e091caca704ac0dc3e494b9743b3495000bebde3a8a374c1dc2e37e7acc9f10793539a31e805a47d87d5e55fb4edfce30025aa9c19d1c6f8f074e9007d39b110e301a2815486cf2ed472c54e1fed847300e049799b82f05574bc0691532774a98671fc5c64f9b0ba0b85450020594b3800ac13d8e66b4e9fdd3d56bdbb7b493a5513c5ab7517f7c6478b7969d3dc811f009053afeeb967618d5a8b357c15cb2e372955af220abbd5c848330224a5d5460040bebb840b2ed84b578c5665afe4e8e38bddece3c1c2ef293ab17feaf90cad00f0bef6c5013f0a87a0d5ff774a59b33d05d85667716050a7949bd7901716f800f7a45e1bdb22fa9d8816fa514f4bdaa51e48fba1fd3bfff6a6f0e92fe7291200c78807e5d3f73a102f43df1847bdb3f6200e7215305208c41684b438bae96900a2d6925c9c823e522f1d7e0030689e15558aaf1a11bf5e0371b9a3423c887f0049bbc6850236990453bfd4194d5eacedcaf77af6abd2b436f7ceffe42f72a500dd6cd23db29b47e92c961eb0b1958c1a4b7c2aeb1e53791ea9a8c7377edb9b002c146f9276ba2ce2d1cd5c84b332f5fa3c2c29c6b473464d913f6789904eb70000b32e0f82b75a2001bbf50eabdbad05dba46240e065c099dd686c97369fae00bb0b5caf35205057a1d14a9208b4f5aeb9b923463e5cbd307566a589f82c1300a574b1a6ec7465525b6bb4ef06592cf422557cdd25a120432043652f026c58004fff96269f3fe269c8c07d27e4a8b9abe38946c7449052bd8370422a2e99b600b68628bb5f9935e95e1f4ab88715215b30dbb96447fef74665097163cd4ac6003bc8617db9db513b1332fd7e73e76fa82c03c60f42b52521bf7d2192bbb794002657b9879fdba1cf631f671ad0a2947ef6bc43ce17bc0bd1b6702fc4bbd0eb003f9e03ad75ce93348719c602dcc128499555d3c2bc9daf52a321a88dca226e00bd3af63896b3c1a821a62d2b6b6a4858de0db7d98fa14eb3aab9f8655db1b300e0d7ffc9b73b40598e12d97ef5948fcf00d571324881cd4973e61579167754008ca14205e921846c238d226bd6b3fa71c88e2684849f9fd094d3f26960d1250041ebd0eddf720ab0bbd40285fbe0d3177c65eed3400afe1853d9d8c53d749b00426713abe51b40d1702514bdd48520a43a1ab7c2076279a8cfb9136c2133470059b0f473e5b61f76251005853cc88185c41f1f003c255ce83d82938b64edee001eb9abd77af3dcec6f026d120ea912219ccd086c9bbe7b1c107530e71009bc003559df71020989b0f335ecef26e9ffddff265d55bbd3185d281e1b74db041c007a9059e2ef05873cf2b2d13a1e288982e8b960b6dc3bfb1e30f0ef3fc848bb008893fed201ba592cd1b929f616e188ea4458d70ef521fbd95e6e8d8328db9a00b97c2b11e9b56ce13f598026e176d7b260f96246f2496469475b0472c33c9800a5cd9ad2a79fcfe85a2ecab6399cef714e5a07b2bd1b6d8423f169316f30b300e4ee605f7b550dc8a103edbcd21b563f67965a687f517914b12181920e4d0300667dede0a9284ab60b97fbd250f4d42dedd4f1aa633d33a00b30f0039039d900918048fd7943a48632f392d89987a928f9fae27270e669d4a6a3fba3b51e0100083e4dae65e60343730580d3aaf639aee68a9c0d6865e75303fdd903b820ee00aa82fbd8503022a50ab4e7adc5cadb72fa7fe336c09e27b80a1308f7f035cb00f081095bd53bf25bfe06a3547a408e7007e74b83fbd3638a340619abfe48a300cda808c8b5b60ccb3346b33114f375877b1127c782358126e03d460c6ec3f90037599f33497267b0390e78f7b70c1c4cbec04780adbed1577445f96ec2bbe50032539cfa2fd3edbcb92199ab4abb3fdb144bb75f4256248adc83f676cd81f6001979ad298c06c7ce2cbd466110c3bffed6122db7a7e0302762653f1425a1770008ea072fe3a92faf954ea2d46713d935528825473b09a2b7002117745815c1006f8fe7d446d8d20e194738fe7f815448fc65e806e9006436891980fbcb80a500f282f85b151d7d5e8a5b6bb27c79d3429e56919bdb7482cd4b87e0b5c396ff00d21a4bb60db0b2a7c80260bdf5a29960e0c214e9ca3174c1c3475aabbc835300e12cdb055e327e04b23d335a61cbe7901aa420f1bb1aaaa78ae49bae0496fe002ecfa52f42611a8b440f0e3fe92876e730fbf3e0bf2c33bc1b3eaac20a5b5d002319f0d7b94260eee66a148f5102e25c8037a4d28df4514a5330b6d916069f0026c98ceee20bb52214b7aeff0cc199be4129d22478b022fcf3c3378cb1e07a00a05bf2e0b14c9289a912d1d42d4c880c0ab45d587c59d185585d4d8fe7e1570034d7101b4321a5d680ad8014fb2762c202378835571424c2a85343398c70210039fd5805b8651a39fc8aeb993258cf940fc7936478ceca2ea8dbed628a922a006b91c2e220608e40579786461aece154447a219a0afc6a0f2fa3b5f74fd24a003875f13b8cffe8e4684323c86a4820e7c1b820fbcdfa1f5e4f5a50ab8ad4f30015091383364e379aaf3968fab60a85f80626b1954c872c34c87842a91da861003ed30245fa845880eb217016bace34660a977d11c124d0f6eee50350553a1c00d569d98c67dc2b4ec6afe577c2b970d1092c65c721b258622e69a623365582007ddafdd9a35280ef7ebf54aa3b138fd2cdd39d5be8d63547e52905ac98fdcc0040e4971a0511199a543e756d053dad063bf90054b28ce202930ef1db91095300f50da75cc46dceb7cf75a09bb4eab2632b5bca5a5302ffe22e6c33e168ccab000683d06a24b24e79d15164f2e18a40ff050947cce7abcd053e3e368be70fee004873befb8696df9403cc513402d28814da8b9095db2846c0e6b124814f392200bfa7479ae9788f0d49c8ff5134bbd1617c3eed295264337290fc9c750e610a0099adc60aa032d31ed7d6e2b0280f9603344635297e34629a8781e085072c3100e29ba18d53994b118d706473cdf522d27f574487df2075c750e1aca5c6efcb00541b94176ebd7f00ddf6d6f06d05c3d673c75514c5ed6c5851f5bd5c028db100234e77deaab208af207d5f734f556cf0a28ef24a7edef0a5df463fed36799e00879044771c3260601e56c4ef47989d55c9ceb5a207eab1b2922c6442b9be0600c11ce46db9ed52fff5f5d3fdd93aa1f6ecd6574ed91747f98fc4a0ba22f27d00949765af0b8bbf4665307c409f04744e05734c7f0766a17578f94b828109730020ccb4c147a737cf23408e598a2cfb44092a803aefebc4f9441e3260bfb25100aa3b8768d2e48d4042747b9454b35725645b78e48143c5d80a93f2815b20ee00c4eafa6b1ff7827a52c541ab5435daab763b0eb47eea2ca16caccd4198d0ab000057530cf078a3b6cf4b2f19ba82b25dfedcacb4d0dac685c73b42841f241a00758d97bcf8043ade451a394ccc89b491cfce4ebc4b5987ed7310395f798f9e001c23f15bf38898548ba2f5f9657e7e94b373f16cb3930ce8f137628bcaee9900d80bb48a9d1486f9a2b7f5a60ca89c55ca0727c22f9bf3e09a1cc1a7458f5300f2d5032bbf5f439ed30629c6acc8e3d19da8efd52599e37b2f8b776dd360b600633a3682573e90602a5af7ab124ef0d7d1b456865d4851fcab37234c7ac99e00a12819e40db233508a200efc47275225afca5ac53d683ebae0ad7da89bcee90062acbb45061247f83152ca0c291ee4989e3ab9d4a1369ec4a1c895f0d840b300d9ebb4546f63f76cb76a303c9e825d2d9262e1e76d62719978e8d0a538e92300dfb8ebdfc414f7f90d80ecb3c1c8f86ef77fc43fc4447a663a8898c0c994d300d74a55e62263aab6b910d2072d87eabd9a5f88e93dd6ed848310298594daf800a3901a9af7aa9ea3d74a4b6cf74c6ee2e3a613ef0c7fb2e110b18000ece18f00b035c49408f700d605f52d063d18269bd5278d2e6c378c184b3b2e1ad61538001a473751863be97f90ff9036565deeedaf88e93849908d22c8cc33408460120076bf48b06c1d56afe9fd4a8f01f6738d68c695b64727b64cf22cddea72f51c00c8e46e22b9f8d7a4bf1040cd93a528f80046df3dadb5a5742e13ec8fcb571200d3499d8a8bca921b8db7855edfa018bc1073ac0f9f7e54ad1c8e0ccea76b57006027a3106cf7a8317ed64b8b0551da9115189e4496201d01a95e32bd7ee2990056c9b2d8f06e730f4ed137cc476131eeec90b1e706d0c579f3c8f983b44d9100f48de35578a1a640e17d388bad434b6d4972eb3b466d722142ad27fa23086200035e11d1d6eba14d0f7f1a581b7f10a029e0308e4915938b39782de580492e00ba83321c60845cf486eb03c4d16b36f62c18144d4a036d1adbf6711e4a044500888070bf3a134eab6f4eed342563c8a6e4a5e399bd7f8e771998a6b8f6511800b66944a4983f06a2dfb6acab0325c6b8ce933d4300f6862f79ed48d44cc42d007bad7f53eb59d84326984ffd372d191ed24bb0e6fda43c1a409150478f4d7e0045a5a7574a0680fc12ebde2d6c18ea0f221e61469eeebb2d2bc8dc1ef4f44900d73f31bf085bbec952bbec8c4b5b48715452f866b9292a17e78086687b6dfe00aae829ccb5e98d946d90648c66c3101c38bb0f93f108c35321d9837fd7966200078f1fb575374d8bad24a753f9a8c7b40e11df8ee0edaf4765cec82121de9300026711fb74e7215e7a818ae9b956f17b43a3a7ab98a2124c8298571345801800ff3c604fa4070adfab11f22ff3d520096a87e67a59884243a4fafc2c48604d006452b3f997394e05c8d424ca431e8f92b298662b5b84fa36fb2e46d8557c0700476714a8839e89f254ce2b9581f120fe58db17700d8a9762eb5c491589d2e6002715c40f1850cd27de78063b163d7b1a5ea0f1576d1e6c7f26ed750c7c0a0900fe2d66cc59660ebdf6c9e1f0c93434952eb0d4aed7b6c1cd9f82490a269d3d0098d5608a5fb91f03e12fc15b9057d527ab56bc5ca32f66c75dcee1dd693d80002a0eae4e45d859f4a5d67a0afda88c656bfe4ab7c3bb22089d06d0b909e8250087f929ce52eef2bbe3e3f0fc24149c48367bf856b45a501d135965531bed7600ee6add214eb42a4cbdd72b0138fc213e48eaad5b470e4205f86a2e8ef0910600862983b50f32b2973ccbca22e0d253ca041e56a86afa07b3e62c173c4fb4e200ecad35f37b2b436197917a0108a8b76106ef4684ca5c6a3bb30e78b3695c2e007a28e5a6c2a64f7c9d0a99ea2c77008b867c45772b6e9d6f94010a8f898de9009c0f0f0b905d5ca5d39c69682e614ec2a633fad3695316acc50b1c949ab2e50028287b6067b85d2a146d1519f8b382f98141d021074aed353f2fa54f1e4eda002af33fb23d9554147431079be702b4bd04dcb7cd57dea68317b72de7dce55200919b5c998e86b5b20cae71ad1a8138d49972bdd4dc738a2aa8e9d06799a8fe005a3c32f0c9bcc078315dad2859ed7a6256ea98a596f3584a2da9f3e8f08d22008e44e248c65bc2e0a86e177e4d2bbe0d254c521c31c783fa8bf25a9075c98c002771b99b777d9079c0a4be4143d03afa3735b4ac32a04fe1a0b1d2cf6aaa540060f4425e3538f6f54918e2c4e9eb4bc2ffcb3ba60da395334df09c205d7c2a0084754690e40b93e4388cb4db710ec6a38e8e29ecb2d0b37db69779a2748a7b0080b3a85366128b91f9415fe169e6dc51ac924d60edec9705ffe4b41051ede900280007e139b4d216fb006a237201d60f71665f66dba2abedb2f908cc89eadc002d16aebac7cc45e8778a0fd85c6a07e3d8ff7104be6a730cb9c15b8c23b5a2003c8ad83c2a070053d5c4bdfaa649119d91fe97588e7c3310ba4bc7d4ba7a350043965ca7da30109eb325015a246df49ab1ad83446366388d3c3d44a1b27014002af51f67c372ae9798a3b02d76ee238a1dc9599e76cda44de1bcf4c8964c92006dd21ec66f875e56ceaf43b07b7cbe30d3b8779a7dd2af949d32dd9de63fb200227343ca76829fc73987a2a5a52496a781abea7c686f1a5280ce09d14d79f600e77bce4ed0d9b69483056a227527e2b5fa4f1450d15955b41498fe83acee6b00a3f09f52a8eb9868dd507eb4a65503d26f61b0c5b9f0552850acf69241f63e008c8d43e2604830d8066e6c25f68acc09e5437bec6a5d8b4976912271ab134200d2f7bbaa1b41c3454f2ae137caf6caf28a680f02a1fbd45f0ba1da7c480185000baa994a3240caf4b7fc3f5ca243373e32902140e8e0906b20c54481d7de3000bfc95bc0e72a29f4c9cef43acd7f4babd8cc5de8162621e172bd92aefdedf7004445683bfc5b9d847907b7442d77776b180e7fd90a984ea5f8d19a56d2d20d00eaf9aa43877c376554e22c202b5b13e5b01ff753475966e281da5deaa3144e00a4808c0c5c4e42c4907a7c631506a499ad94b9b0d10115cc1f54930085d6e700e56901e9916a9d7abed3a686c237b7520d512413e6ca4c173349b0770997670007969934760941cd30b87859300f84b5c08ea0bef49a1d7a98f7bfdaebd862001923cf7bdad045a9a1951117e91b8520f4e95935e21c10446bd42f19d1ab280082109118f0da06aa2919788e28b345837d9fab83f0ec229bdab7e3ef873ae200034151fe34a0f2181c7c4f3091680edc50962b4749e26c4a4c4fa1c448dfff00c7be0b3e77ef5b3420192f711224494cb2e2abefec2d282db38f1a5c46c8dd00ef972742e893cbcb8ddd0d489a1c40416c6e53e592073b9c0c98fa1a600d460053306924a2f2cf421822a46aaede8db116c4712633a6202b38b09d4222806800dcf43107e74c8becbf506093e56d3487eaaf16217fb0b3b16b67051cd44dd100c28dd3cc703e99cb016ccc7882efaca7f170e1a02f4f3c14012995fe8ccc7400e41f7a4b7e6089fa9ff219a33215609d668db202e69533b0e2ce9472bb650300987db09877abc5eea1d91f5f4def67137e3420f5f9f8d2ce37db80885e63ac005da4d98b2d58bed6ee1f6ec66585fe220ad5fc37e4fba7397e3c7149354bf600bf5c7220eede29e849f50c73a42fc4f43faf97cac1b0f93fc6e3109135e0dc0028f37a98b1871154d9a326428509ebcad4e28a6eb394b052862ed1dc265052009508de9dc5dc836cb6556bcc868d806a07c381cebf1f48932b70abffbb9db900544b5b5a5b7904fb6a40e798c7a4ebfcea20febe38f4fd3edcc8bca8ac45000028f83d43346b937072d5b15d6e24f506fb214d16ae8d5228aa20c99e7bc7fa008ff7912ad16dda451f91f55cdc781e8c314f3a947dc28fbc3a10d79110848400906b9aba142380817a639577561810832ccb4cf53936f7d3618df72e869235004a8e3122a95c311b8412395bf8c7f9beeb70a49f4a6226cf19ee4e31c8587400b9cd3f9f6551151d5e1bb8089e4e3bada8c92d9b8f109eb1be6f6e30cb237b00367a0e02b45db1580b250fd0cb3cc4c5bce7d8d5c9378b6bf8179dab9847610034793cc98f17cd7aa343052f297e6d1d902f45b1d8d0448cbac6360ded2c3600eb44f9bdccddf10cbc32aabb910baccc731677568d384172583cc7a41200dc00ea34dee172dbe767487f099691605390d99530ac8c5d295f2de9ace6c4f1ee00f95b8340b5e2c86930fb908eabe2676ad66c1b85420a13c93ca628e259eaef003931ff0c67a8351e1c7bdf49b80c7634e7106fd9e0e456fd4396fbff7dbc1300c902f3f65ccde219c5c962526fe0939fb01d0e2f96051a56852a11ad00c00c0028538ce109f8d254a9ebb8dc9247a062157dd20dfdbec6b63018afcb25837000be7f486c7b8c2be90c0ab297a30c4b9d1857ee28be1943641d0079c3226544000ea2381ce1b31bff0fdb348e9c133488918a1a8db5e23ff8264fb3677ec35d007ddcd36736b42c7e244fff9618bf8d0c6ab2cc04d08c198ae6632bd48d8bf10086f071ad705b5f02f0a1c40fbedd2d547046886ccd8b420601e3a8c592d40c0020eaa5c0f8d6ed05de99dba852deed9da4f195e1693acc0e6af2ddaaab2c64003bd3702907212640b2bbd332a04aa96ba5cd9bc08e9be0b44f290e0abccf60006f51dabfff5f2f0d495b353356fb8d360758f6d5fa4723282dea778dbcf8d800c2ce71cb22681e38fe00aceb938f0702f94ca3ad4d1ca0985b9cd534f59ed00029db68d3438a8f27cc3002cd386d803f078a9a530a97fbc3a9f16850264688003dea46b041bfb11149eb77ce6dcf0d51f38b25317e1bbfe3cb58fafcbf0fb100629f5adb4b7162cf17a59d848b17bf069e2573d2eb577a8ae93cf0617af64c00f6c5c1348105f828997e61de4cfdf5d854480762d7c4def811ff18cf0cc091009226ae4a0d34822f3ab1991b58c759f0e91c6ee4762401ee3f51a1bc9914d6002ad08057c361fb18c3196795d10e39e618eac769418541075caca92b396a72008d5b93ca58a690529f2bb2f93b9335a603b026a0d11be969b455f4f34204b700af1ea90837d36b37f167c9ac104e502b4af03fd6b4a74b23c4aa970c169c6b00266905fb3e3549e3c0efbc005317498c9a41269817fd4322178afd7282c1910035a6aeb04fb23df619e70df830e6a9924d8e9ddb2dc623b04826ee9b5094450068459e47e0d04b7b539a833220ad3f9c49997a33631bea98436fb9a12532a80078e788a59add53546c4e3a09eb8734c875e855611cf17f45db8aa5ce4f82ba00f308de1cf83d2d3b11a73b465ac7d0fa98c23827e9a9bf6f8dddc28df94b5b00792acb25d0f2dbf010f9496efa1e24bc260e14ca9ebe08a892d8215a9b401800b24372fb54330dd6c6725615f095eb879e65cf7c13821b63be27b0904eeb930097d29cbfee8943cf50450e0377ddffca71c01e06c77591128b90bf7ce0fcf00046b0434e30d84d4fc3a4d7e2724f63ff3aa4f3ff6c15ba9e526c4bebf1d87100434cd395fbdd34a5e7097475949168a96bc8d308f8203799fffcbbdf4b87860063f6c5900ed25594141dd0f5237c452b19eda62e63190bc71759fbff11200600cc868993a46ff56c8d180beb7ae3226ee5ae2593e06dce5795802661c5a15700615023a2d00aac7e18d9d89db5a7a7b1a9c12e1db770bf8063e569e0be7b3300b740991afaaec45680ff89844a8b91c98d6539b25b7c150ae773dede1e05b90031e9a9d1331cbcdd63d300aa59ac64e90199e74bcf81c9de2f00a76349e8ac00fecfd5b4be12d56307831685104ce448a8bf9ab75e1cdb3d7098d00a816932000b1eeb3329099f14aad4b766177e87ad47991880153706552d1c8b01cc4d9100e37e0c88bffb75dee15053f9f1b58c8329c61dea938a220db170059dfee778006c70495abeea038511756c3d3032edfc9da35892fadbafb857d549908298db00a733c16957711c2e01b3be280210ff2784cff59e20171347885ed0635dba230023f47651b1ffb4a3406376ef30514b0e4c603fb1388bee1d78870ea6e0e1840080a09899deb9a875cdd84c795a4667e15d4f8862c88f0b4e6788009d9b8f960000e5130758278f41ad68e32e17d6ce73938530d011850023dd82664f323c4400bb42ffb06e8791d0fc9975b154cf476621b327713c3605abf1f6de75c55e19006a32bc77ecf0a12a0daf843e5faa227b78887d46acf639866d8bbbfc409e5600ba8cce54e2a1cf510d53986d43d44091603d7c833337fafb2bed11f0beffa100368f527f1ab61825f69fe3d623c0043c1aea33eb8f3db5fcfa597eccd520af00a87a533cc4c3a2c2b28472a510e575a5521e13caee8ad05362f50aaefaee4a000d4e56d9b42d3f59834016f2b2aa312051f6d3be00f4dccd201776948a45510064948c19ff494fd4e1d34dd49c2a0550dbb194000bfa92c8666fd67c282814008deaba35807558c3d722e821cad8a1486739a1b78134dfaddcbcb29f0d005300ecd2683ba079586d698f24220285fa75b1d9c73413cc053493dd8a178a2ddb00eecfc96566332430b943ebc2f8a5ab388cc861f77d6ac2d5be46da6920d7d4008ce7275b4a6d53aef14c248b8487cf58916ad65d174533d7cdd2d1475c128a004e2e22e10d8976463c3628f0b5e4fcbab781135cf2a313d4a2b46b89d2dbb2004423deb3e1e852b8e58c1f58f3d4968cc886ea07d7f8953932d7e20c69215000f54e0dccd25e73d97fe5346f458da7b54fbe05fa3211b4f7cddf8b2564745d00e77f52e47c33d453ea7e69fadc56345d709b6c738a18798b9f38a95717372100126c74005153f8bc2d0f3fe3a2b7299d7319fb9023d409cb3a55714c1b7f4d00bcec5151cfe651649df78def9a98689ee746534f282ea7ec5426ddde3a520f00167cbb6bc5b18508a0c444a22d460ce681112d16e8dbcc52625a206feae39d002827a63b4b18bd6c7f493c612c025af36f7d87cfd83fa81e7e578fc238dbdc00cd216103e7b914b8516725c151435ccab6303a29007f05d32a1ca70d24f38f00eef6ccb1ad3bd85b24d427bc5c42f5bde22f4220669fc6f7ce8bd4f3fbb9dd0021814487ff9336aad90355bc56bd378054d4cb3c81b5c2577b512fea6bad2f002c71dee18aa0b4889bca97780aa52e6476e9f48f50e5993cf17f87d5e33ab500c99bfa563a2e777f8df399111cf1dbe36c53d1edbf8faa1346bae78858ea5f002e09426f7bb71f56c4876c9cab1f5bbea7d1ef4a633130efc98ce20763a46700bbc2aca4e87d5764bdb94e6deecd6b7d83310730b003758fe6a7465e2cd9d90018766ec1f7039f437d4c5b36fc8133f21147c2286c2b1ac9a9b8a5b62a4a7a00bc5c2f5e1231fa46775e0a6cdb779672cb37fdbfc791af0ec99a5ac9b1799800e8fdac8557f9e8741036fa2f81e3e538c4132135e51a67f8f3edce6c64de52006d61ba08ed8601159b9ee6020856b8c26a7d17fff55c4d4e22e5b21ae8a87e0045ece26099c8c0de44f9417f0b5d2ef7d5d685af957251d237263a4bd1e3fb001d29c455a2d4fcedb7378be68ef08b4609230361b402176f92689b4720892300dfc9d0f4205c0c4560aa031a4a59d7e7d13f76d199555dcee14af64efd8bd6006379fc5ccfeb0506ea687627c9a9e20577fd6836fb70014f1e165982823cd600f198df5cd9d52c21fa8a8f10b2a53f545d70afb1ae4c2de2baf9ea6b02443600b4f64da9e5343e8d53bf0a358d753159be02eb0579084f74d09c203868c297003a434c76394ea317ac8ab7427fb91aa41669b4dfcabac29cb988844bafbda400be8599ebd7346974ef85ec7b61b022e8e2fc7b5124cea5c978b8db48b840480054e90b85373d89106516dc4be5f9825bf641c6e5d020496312cb358d807bb90007115c806c34ec8abb4efdbcd2c42849642ff4ba695940ea12e4dac9bbca4300f40328b566dc819747763c21ca3802ed822a0bf4b165a7f0a5808367f0297600ef1776182034030f923b9a6e9b15f27ee2c568aa90f131745ec9bbbab09e9100dc36b3bf7f38a7626ff26548d1a7bc1d326c71d97182c31f600f729276f8b7004e2abcc4e4363a69d9ff8867a8d04a3c94efc7c40aa7dfac4188b866e57d1a005759697fcb6bb9a2c97a6a0965bd4122c4bc086a450dc137e42b5c40cbc6f40019b2e040db33380791f5036161c7a0d7676d7a123a4ec6bb840432d196fb8f00f1323bace723e19477d36162ca5acdea72d59fd573759019a3433ae03f650400cb6896e8630cb8c47bfb7eb59818c500d89ec0f3d2149cb20d7adbbc2391a800fd677a3fcfe40f2e664e49e34d2c978be318dc9c5f4cc52677591d612c8b63004eec83f68dfcd09dcedf2d3b5d55a5c472965ba801103a696c34a0039b7f620075f53a544f77e33cb5aee7b26a36a39a8bb340222729657e97fb1418019bf90071379fd946b79d90b5e79e96782fea582bbea1c8a49368de677769c1a01fe5009419f8a1a0c5e53d45d3c5338a5197d4ac731539e9dea6e4a5a5c6888be16600b6c864b77c871f5f36cf5a201ada815b4806ea706a7c7d2b8fac8b6eac4d5f00c08a7e49340b6e3d99800e4b9f96bdf4a11503ed868604172447ecbb01fc8300562b120cd21f029dde99fc0a4096e3d70018832d2ceb8536a531cda9c88b7d00033adb7cd0ec0e19b9d2904abbe042662e3281f24ec45971238d9771d0856200dd2cb96cbcc6d18eb777e5d9a999b35e540148ca22a150167941cb192e5e72002908137dff8bcdcf995980d6e3bab2f5e5560075d9d0881e733473372ff67b00559fd2f116362b4a33783fc536cbc202b0bef062e6e92672c6e568644f3ebb0060188ff4b83592d07761ef285f0ffe82d0c9f373d0e3cbac542dd7f81714050071646b71b35eb4f3d0b61fae30aa14c6cc4fddc85006e588d7d16333d3aa88001c8771f58b812141734e85ef22460d6433ef89a076bc113c00c8e1b286f714000dae6ca085407e6d1a9af3b8649840b862e2f81997f699c7f46d8eb2881a8300858830f16b02d2975210383c257678bd1cee234be1228ddafe96d9ddce1eb100e36d4494e1a2b8f7867164f46b2506e10ad912cd9c6f691bb6cc587b8eb6f7009321bba0e1b8369a2c69e962fe54481f29a8e5dc1976853f95aa408d3eda68004fe48de08fe003228fcc8b8584f507bb6e9cd8833c6af8cd2d909e4cb7af69008f1dc87b436266f8455462a06d211b6b6ab0d222369522254fcf3bef3adbe100a8d4ed31b956c15957b5cd3fd2fcba052eb616dba0e65b1d1752f8ec24f7a700d5991676c7849c1676f6d395833823258dc308291583025adf2c02d901ee820052069134d4dbc5cf279e2092c9680fa11317d8847df95cd9bbdc4e92684dcd0057886c8b838eaa8755200ccf618d7c162e3ba8ee85e571440455f655ac62060094153108b93c6de473cd4c32b44d06c7ab91b6cf03a0678356d0c9a718910f00431692e27d1acbf24fb31237a8e12dc800a415d50ff22013701911d912661b00dfacf122985ee39b1b780162d31d902e9ee29bf9adc994d114ebb83149a704000a6299018df64d8e37771dd7a0153a1d5a8b3b197f7fd28b5453f140c0d70a005ac216b4faebd3c0a77aed6a0743db02c642a7e8864c5736cbc727404bf51f004fbd734afd6b4e73040e7a55378a8081c9efb2383983a937228efceb149da9002ac48f444550c9b91f5960662df8849f0652626fee7388fa47e2cb72502c4a0030e37fbef5cf219e20f00caeba68de8f78e9395c1f2db0c650e1c3d971b13e0086c935c1a442ac4160dd3c39cd4020a79d2264834847bad3431dfb24ad0fbe00acce7e058d76bf1062bc7f5a2d968b46b5f2323a22dd07d4e061a95c8e1ac900f8d13480099f27daf38d50ebd294129ee49fdae8510eedcea80997f7677ae400cd2e7504a15a9a5c1689cf32c5637cb40eb1197c2333753e8347fd54c228830035a226a780cc119bacaa6f45b7866c4b2d14c438dd0eab13e59a5ffbf4284c00f656d1f6956968b084eacf0b2d79bb8cfd04739228b6828c5d686192d297310094ae52d805d69677e83206438c423006ec64e695834e69aeea0a60d3eaf3c20084c995514180157daf8ae5d45a6959d164fa2f8f8b53bdc1149068a3ce05dd0038a8066e7e923f35eea71d2b7b7d14c881db5598776873c29b2afa421aaeec0025278c1879e0b488b75abe36fb2e25dbe7cabaf1ac93d0e91eea9736baaf25004fb8158cbe5693ffe297877b9460ee618e2fd0a2535ce1558e4669860e7d55008ace9da1549e4f69dfb4dbe37a36f37f541906c911f145b524a883b25b408e002540ffe67f8bf77a5205f22330cde4308ace93a6778eb8d31a89e8d5b6d09300bb42cfbc828f89d951d25b21ef3aa0bb5c05ced89cc475e9c5478ba7dfb45d00a11d26b8349977d49727b92c25fe0fc1544069612bab63b38fb50c65ddd2c200f014e43fa1c39c9642cfc9183b758edbb49fce565a88c0400c2c78c804cfa4005dde47e34fd710414be60d392257f86c4b1fb5eea17a9027dc125a9dcfb14500e89f0de397a67253fcd50c2b6bdc90eff0ef9896221acf4f3a9d47906012df002783108be35105461d7f18e89c15a02e591ecd4a0ca8fc8d7622951f3584e5001bd9068889cbece5c404c503c80a0412efee1b777cee68f94bede96150e2c4008b1f9cc77c1b729972ea4c2be5498fa9fe981f76dfe584a4cce408817a8ea6004d1f851183d0ab82e3b6b26b53e7468741882881aa7b8100a26adc99c24ea100e0cdcadb45a97901333019195d0abe7b1a4a07bfbc4fddafe260e1391be46d0005e7b7e69cd52fcbd0a9ef04e324b0bdb7a71ba76bacb9ec84289dacb3e4fc00c90047b3f00ee2869e189c0232be855a09b924f9928ab4a095ec83a8828c2b00dcb26e115385f29e8e9554ee274ead4dbc29b903a39f64911c09cb2b2a4b1d006ac0df159d6735b5b63f7674b8f427d04657397dac6cd0c4dc80b3d879322400198a398204ce58a37c33aeff811f108031773426b23865e13a6e548eee5db300f6e9c8d6c8ace131fc043d3171c215bfc076b61f9ed9ecfa7df9057761575a006d6224cf457a424b10bff4d8933f9f836c8dca4f17224f7accfe17222737770056ee3564186d491decc10127780cb5d27c9b2a8bd7d1aec39754fe0a26d64600b399260de0a3de3342104e1fda6af33438d8580ed1a6c38c678aaa8aeac05900b63c3c5c5cf5a0426f52bbc33f62dd58bb678f68074f3f647e3cee83eb54e900891f86619786a11a54f8204d4011434334928a2535167f79ccc43c6a02dcba000026e3605a4d07ad751fcee3ab36977977997a9abf83af819b2574afab096500425d3fd806575e929a043b11c16f14db135b9f5f61ed117d91dcd47c08dbf3002845879117c020cca7c0837422c77c22357755f378e3a42fcfef494c90389600eeae1cb6278265bec8f04d1268d28ec539fea0b1efc841657023711fc1dc5c001d4f3e43705236dea41e91e5475977e7168faa185053ee7b1cdfba043e62c000e4c9de69b557c17a07edde6f0f085177b8c414bfe053d03d49194910159bc2008b2306cf202c50354440c1081aa63ed7ae73d55fca5b3a506a3e43bcba885f00e38e3d279ab4f1b8a9fc8276ddee435ba85e24f1f8298d8ef3e21e4b12851800ce3630a0ed27511881f5c900cdc97f10f510bc6ccba20832550db187724c170050c9e27bfdc5a4d43b9613b36d15fa8da98334541dbc7de09b90e484c291ad0095e3ed00d73961700897ea9cb5288f9d833172fcb067948535774f47e1798100d55bed9527725199f0eb9f4e8f7aec38093400df735a6e5d127e183c569ac900de74e10f3776540ab47cf3a587cc636c1c1d994763bc1f508e09c1ad60e7860018bbf2591a4db0e9894429168fe5c5ab182da58a18fb457cb842312b74a088003b475a492439900a9efe889119b98b776f29320ecff27351da27871f15d75d00074a965f5af1c1f20ee161a9b95c370d02c91811db3afe3e566f0dc9c7f15a009477f2357ae8c3d9de7bf323fde222a629c1e5e5e1b0a3805d699a7b99526d001ee46efa06bbf6ee741dae30691fb0690d62cc65b45cc657df7752a6c9b1170052e2830604a2a436a255585c345a1b8f69e58622b20f2114f09ea85b24f07900226ea1bab77737e2f579b8c173661ec7212c7534943741657342ef51107e4e000c35fa9582b4c083b8b0d3dd31f00272d3ee43cf87e70b949bac6ffc5eaa1200ce4584fbc779943018b7b21215f7f0e21f64a511aaca445dbe0dc9e00ffe87008da1a67447bfe3739575b2783990fb7fc876c45133dd3b87284a51a815f3de00549e49810f5a3cc089fecd0313fa50206be90d597dcf6a552c2e5ba21b0a0a00e031235af9edff292b68d15e2d03273f740a8ce91a0a81e5268a3a4bb7203900428fa136baa74e9dbf9d9d2b50c77594d257e075312c24b5c97e84671b5fd100e0f826a0dd3a4d8534f0e43db40914b9477574498979a7f6210e4f4cc3933700d3cd089fab37f1229321c0ccf25ff48194a631280377e7b22aefd973534c4100a282f533bf013fdacde51c89fd031a3a1fd18d6dd1dfafe76eafa68939ba5d00a884eaa02747fa434dfcfc8236c803aaf636bd0a67945e4166f8f30c771f8000ba287617c2c37429f3ab774bc15018a27b4a03c786dfffd1c496baf59fceec00553b20cb20d7cf79ad27fd7ac079e3089fc1810e150f89d5892ef1720ad96b0039e3f4df715344437ef68e67b3e3f5e48b41f2c6ed0c221da5b5d94224856400d7873c5213332339eb9a16f56cdca3e383865a6cbe3c23f8db7aa4c175993f00c0333ed6df3bd29b9f06acb99ed14d383c9fdec36f552de5569fd5a45b88da00312cac8bf7725372dff232e5e0bdde14c832c8635107010132074c8bdbfe9d009981aa13e9ec0c1fbfb305b59f7c7228e85889542276315771f983eaf19f12004d728e799efe8ce142288b107fabb8884e48730e589eeb554584ea4f5db9f100dc7663cbbaa1ffadccf3c8d61c152920a1bdb44983d445e0d8306a487162c1004f13a8cb689be4ad1dfa86291ec9fa2a79750a0d639793c70e5e3d92fc80b400814442a99265020059ccdcb0eedbfcff4564cf583cbe77f2b7a5f0296ca6700002252265b875591025b8168097147b503e6cf5e792f579ef5140e15c1acacd00d8e1550ed1c361f726e4f0b098fc98e88f6322f7e0f5d19c755d64847ca280005a18fb81ae368d65e59180c50c2720cad74b857370d9078663156daee8f69900901045a99c5c2ce016c29e64c3572bd00bd1501d55a85a0b6ec06401f5953d003ad6b28024103e3b0e60a95f1116b6890ab7548ab064fd682ee55aabcc460100ca8d2f2323937ea1563c0967b1d9a84489ae6cbf97c11e2e285d8b3549afaa0069b1af37d9af90554a650774fec84cc6adb178eb69b44a514e938b841b0d6300d3d9a75b6de4ccbccdb2735588edcf5fff03e187fd16cb30637f45ac38690400c06204a30bd5dd81ce1ba60e7cfe5d397b76e609ead0d3b08c2eba319ecccb000f77d690f7c1915308591bcc50102742e1380d6dee9dc4a137815b9ea89cf00071e07e58c8e5aa7d5a9386c717e902716a7790082e5bb2af315a0b2afbced5000121927156c85ee1411953fc70156c3941f121a4abb89c21294e7b19174dc3009659380336613766c130d118116616722c8a5734b3d9892f57cec576195d21005bb93aaf65ae7891f12a7ec0ddffda7f0d33c205c901b0dd2ead97cb5c080900e1485b29b4f7c77a3dd87da7f1d2bc218acc5a6991d746d92dba54d6a8802d00ea484d559adda56ce746b1ff7dad34816d3cdc80bb501f9ed3dc73eb7a896d001852840d7e0f9e367a03ed7df9961592ea86ad2ca1bfa93f38115121f61d090056c9727830d1f6fd3b67eed63b6d20435d17068df9b12817c914c922d4445e00a84e14fa07d2782593f5aa51ad3ca2ba2a321d2f2f242dc4bb73e905a3615100d949681fdc3891bafaca80b39f99592d7276bcdd84a613ad1dcb34a99482ab008543351780e4e1299b7bef6c211919223b49ded65f824b1efa6728870d358e008cb90a59031ebf107873e5d20c43259f66ad922c1cee2d05804d9134890b8c00bc0738260dcd15798b1d5f79f5164c785efff6debb0fc660130d10d381426200f6a6f1059c31519fdf27addd971c50478648e3e00fe6be7885c657ebb1cf57009fff6bc96ac9691e792602dc322b440bdf7e9fbb1b7b3a1ee2b1e3ae5b5f9b0004c6d21e6bbf4893f40f00cf6058291139dabf32fedbedfb36bc44abbfcbd70037946160b8eb62e53dce5d4beaa4745875731ff11ef9b725e59fe546b7a2b30057ee6ebc8ead7b87b217a673f128abb12f01a8ea9a05296c408eaa020004250075b8d4d6e69bbe211eefe570859a3015916a4c2520409a241705fa4b5651fe0055674142f41b79ec8eceb3b46e4833032c078f7621c03b46235920e27ade8400de64846d0548a9df5d998ca88ccaaf252e9e42a840798220cb814c0a0db56d0071a616d0fc2b01ede9b1f35dfe90863a2e92f13bbd534e19ba301b56c1256a005d8a6ff83e19cdb871b0f8ee93284892988b50eb0361a8038c39dbd43c347900f340a4fe5785a7bb473f2ef3a2372f0336abeca51a2b42b4fbe9e480a1fcd200c6c6152b203fd87700398ee5a370f3ec9b33a321d440be1c07facd921f24130096da2faedb232572b155c579ba00f8a4cb5e3eb468908ee50ea8c563e9436b003c1f8d0f8105032b9ee97c0249a7a6019831e3ec25e8bcbf8a66091f696c79008c07a797eff4c6f195ec9cfc35abf1fd83f1f3d21b84061f047e81c8b5614a002fe8c1fbe81164f316a5d1082cfe63abaca4c8312e2324df3dbc8a3075a82b0093ce75121ffb69ad3b2f2fe2f96b60ae34c5a8dca1679ae0a97ba71a5e875200b2cda21d36139c48a7545271d8e35e8383fb2044ffde4a31f9284ff05462d900ae1dde6268a2cdcb7392a69dd4f3f5bf54f596e6a416194365654e8952249c00fb059760095430e0f6947833a1c9a029e0fbb45b5a12aa6830beed67c59c120077eadaa87bcc2d48371e1debb84acb24ebaf60924672c06be19329523ad3dd001c5c1488df34576fd71a1ea14f523da591cce78bf99b68a3dc073153b51541005edce180d96c970f3fac19595525d8cb0e199eb7f18c3350a14646f65b2d6700126af603f20a52d09aaea26590313c1b198465fcdf1e35ac7a6d504223bb6500c3a2095a494f9b53ab9bb7049b70395f2cd55aa0c9d02002ccff7d2b962c0b00e7837ba0d504acf3d066404266d64dc25c0b74fc6c5cb1b1bb415cbf839eef00f447852f270d7ed38015bda97c4caa5af34f488a435caa450e69a4b51f68b200f0f3e4376f23414a4b3b204cdb4b10d9dfcc29a884c343bcffffa8949f885b0016250101395aa45fad155d51104e3a1a5b5d3d70665daff17729c7d62a4b790014e5130600c40e267643cfa6cd9bc800e245cb0a46210f70bedc20a6bf68fe00d9cc1ca76ab8f9bb79d1fcecc85480f28888548b84b5f86f0aed624b891edd005a35641a4b5c6a32d32f64cda3d0b58414e19ff3630f14f3b15d84d10feec8003fc8fd9c322b9837874c57c888487cebe1de3a28d1c84946c52efbf14c6c9b00348f4c4495c7ed45ee3b4a95eedda3b20acb9cd21b9bae700f4fc5ef00776800484a59493d5effc5c551beb0911df58e5ccfd269c7f7953c16606b9356897a00dc8083fd9a528d14c04bd70794d8f5c619705fe7891b06f61209451436a876001c2ece5be7dfe02fcab3988d5e444bac6d7c72a8bf00d68f9573fc381bf6a100e33cc3d7387be8b2f8387c2b3f6ac95e3d70d100f4e03247ad7e7b585262b0001e688e18e0bd51a7fe2f963298b9ee790481df2411d230dea6872dba152d0f000c0e7a095a887f6785da100b94ee5ef3cee3b7611c8f0845f314b33669edfa007d10a76a312a3919d3b56664c270c209f2483f7a060c5c33919a83658b72cc00df32d1d20d2d634eecb63c1c75959d41f015c118cb89f35d74f7a439986cd1007697b22233710d604434fbe305194d80c89692f85babd4456187501265baeb00f70e34f9ac7ed0960a0945743fa87d9f66648d8d4d58ba98f11325920286570003fc973ee5b15b62a3e4c3ad6790f93417fb909ccf836471c5ee37eae6524000080471db81bf76583f48e33c71908c34c72e38a102fa1894196224969c3ace00247968c0634f57eb8fb69ec5ac57d3dea2e969722894f42c51dea934f6c58300cfd2c8cb1ea706df0c2d2161d8344ca8d548a0332e6f16c3733c21c1a3f4a40009fc64992c94a91ecb75e4682cdef5dcee0192be45936375d6f3cf0f1c315100afddd8c17d26b31698bee1d143cd9f4435283881a8fa848f12c46f8c99adff0096aa8e080af42f98489318fe6e0d3c8cfd5157f087f1c4f8689a0543c3eefc008ccbad23c00f33a9d3fd42fd8ad3c0a4138cf98572b8d10c9922afbe74e5d000c4a845768bdf3f6479903f2c99e0b5a9cb253b1197969f7c9480ba3c3510f400452cee753f7c72571f0af35ea6d8f65bc3ab550ebf25b202b917c8226e7873003744e70783df66194b43a79dcc5b074030f555328bf14d739a553d6a8955100013e305be380c01ff7dcd890db38784700ce970f98b47bd45318676a50859240074cb6d97687cc7a35801bdc8ea9a274e67faf4026dc36efa1f43e87becff9e00a0f34d26de79ff550d5a0f3f043cb650bfcc3b859689433fd39e185ba526600049138bd3ac7461201f6d098a13716cfe7786e2343c9047ee16ef6287796c3f0021bcd0bfa4a513bf32cde7919cffc5a363983049fd55b0447cc533c1ba01ec00c7580256e97456a298207d4b85ae8c8a68c954a12514af215dc1bd066ac4ef0087fa79dbb00a1f5a9bbc3f4053bb29e068c80823c4ea6600ebe2a7767b8f1800084da308b3f724332c8db48b329d89c54503aafeffcfb02b8fea1c3760aa0a00a24e9b3cac2b6df80a0e30094d4512a3c9f106366a18270e0fa3c42c09867100edcd31df617c8aa9fe792d7ca283bd023a0a6d33cf1c71ec6133f2f2a1c12b00783626e95c05ca9777e58fa43404d0ce4a3290cff4fabc6c4bd3f1a22dae2e0038f4d067090ea12cf6c39cc0c3ba4940c4f3b87a7c45e703c86a0a70a35dc2006305bb25962ccebb12d363801fa15c640110aa5b0160a72e207ceacb591b2d00e62aad8ad4f50dbc4d071df32e80d94dd2b78f099934084480745474669f9b00f173d49d810a6f1927f57291127c0e9c456f97a0774477cf6312b07f46bd7900c9e967e40e1512ab0621eafc81a8629d038133107f4e756a697c80bfd37ef1007f2198f3bcbbdd4a2d22a1f07a9f6b9caac9c261b27f9d5629c91f8a3c89330093fcbefda743def10075640c8e866420f73f7b27bef7193c9eae047df5f120009098ad1e1bd4c9d43e1174ef0aa9cf91cdf95049e8851d0fe349b9f263694d0084f2bf35ffa68a1ebeec606e59c83811245893fdc4b0167a0663ae3bdb4bbc0047118e1e636eda3e9ca6e29459cef08ef9fa4030916275c0fedf1698c249b1005e4917eff2b8c17bad3750509b8fd96cbaf74784a29705458fc2e82b136a9e009ee45ca56cd455d7edccbb9dc0ca52ea991dce0e949fd0bde16ff6723ab5b400d681564c5176cbcf4cad338c25b22369ce3e5439d68746938c874d94429e8400335a5233be4cc58d698c0e1e31076890c41e9f9b7ac09a617b7f46851c92ab008f577c913cfc98ee68ce8505fcd523324fd79eff4ee46bc737c28b9b846ac3000110550e406d10f487f9755653494d3831c2f01e1857bf8f03b3b2ba6e3e1c00409f870c172e846b66488580436650b63793102f6035d6bd2d7871e3f48491000450ab1c16aed26e03188ffe7235e4feaa4e5893cb8aa53bf5af22c091290b00e97d49980857c8f8ecf3a85fb77ac201323a4ddbe7b781e0b8ef7cce31ce6a00bfce8e52b89aa43be77b2b5c5b1554fc037003cc2181bc69ec3cd677f8022300e77e7c6289e648120d36fa73c4c32643c2ce45e0f7f87d9ab941e31d9c09c300b2d9817adade793053bb5ef10a1c853550e240425d8156989fb6880ddafc240064456c12bfed37a73c7fd99f9d87d8769f258c5876ff4c6695329bd778a4020084132637a19ce95fe5615cade2efb70ff6d66bfa0ccc2a31f1c445dbbff97a007180b017ca41d6ba8c5e629dce33c40dab823884f6cb7b8d7d425a1882fed800ecbd29191619523ddcd98ac3810f2fbe921b11fde2d74f154884a5ba028dfe005a5bc815a121c80cb8404c6da0515e340e56d81ec282dbc847e3941ebf07db00315a7df680de0062a7d210acd5382d224fe02e63099859c32134cdbd89c4dc00252f0b769b27949bf436dff7d7ee8fcf848e2294dcd30d8b01acfffcd7d2e9004b6b8b18e49995173c7db827c67887d2630cbca42cfdfbb6234b14a0717e5200fab9ed1289af84bfbc49bd41e6019048b5598be42a68bafc6f50fbb0eccb2300516a0843a081fc1d053ecf08a2aba7090a447f62dbe4dc36372d550f6cf0390084d7f2ab7f53bd824ff1485cdfe4611f900473607067d1724de1cc2b2c990300c632d82ecf959192d86b3be3ad1efe84c52afb4806e20f0e96b8e6ee00666f0036335db00c5e9b252dc673b65c97d5a18c7221d39de87116a0b9977f8b154d00ba4228d2a8ec9e9250b3feb6b7dec0b8563727d74369bf71166e518bf0b44200f40189dd655456005f4f8fbdef7041dfb95f24e63a96d128702cf9d06c5de6009e875dc0e14c618776adf98e0b46914886d0e7d57a7cf1fc57f753b32390eb00dc67574fd0c76f8b6ab835a0d3220f3822887a2d75f894a447d6eda9dec333006de68695aea6efb6985b87defab7249708d28464ab3f256531477c5af2cb6900867b05a745e094e548fb11861e128126175033798ff97fcfd85ce549adf81a00c9798f1c0bb3de295effacb34188f740232794ef4e6683e443290b719bb91c004ee8f30205738087b26eeead05d41638bd06c8e32fe0a26f98da607a908cc6006a5fc120177017f78c6d3c1dcf8f15f18d541a7bddb5765240f811d3e8a2e0005ced16d216e06cfa470b22190ed33d427d5a111e9522476ca1e9bf1b8bd35900df4ccde56b233b792fc7d06c024e9dec3655324fd3340e4d614d01c14bed120001356b68790597d23ceb9b518806989655f6de3c56f402ddc1e6d2c7fc01bb00b54be7093d957be98a0a2e7a50ddbac80c90e3a4c59bd26b7912c4681e65fe00620ab37de60684799581b14e1b7c4b21d43282e0cafdf2ccab926204652faf008acbbb56e331e27656cf684f1b8bafb68d172ab5352fd74580cda3ff2b083e003a3c273a67376fae053cab14d4f0ee76e051f2e07c487d5aa2d2ed74650ce7006c6b65c1a49200eaadf2de191c69037b9fe039fac3f63b2874bb5cb95d1f9800970dcd7641361bc5020833349735daa22ffed70e711513811b56b451c05a5b00bc797499587a1919ea5da143531dd6da4085ef10849e672d93c6938ff155b800177c713b53b1f4cea11d743acdc4c4bb7fbf7305e14347f6a74194a61ab7c10071bda21958564f4915c9964aa5ed4dcb5fecbfeaf3f295388455de00a1cce0005b8fe6bb4a5c584a84ea95ee3bdbf919f3a42207e035ab8a361e6e53c1a4650040d16cbc60a87ff4b3011a229f068d7aab3624c8fa348dedca23be492eb88e0005d3ab34c3a32c4cef412877b5ab2d9d42477dc8ce95a11540e3cf8905d42a004226286fd9f79aa6eca3442ebc5e7db7c4e50fcb0866a0c2bbac90808a26d100e364da274b0a379f117f799dca4c98f5abb3c757799dfc4ebbecd31f8924860042fe7d4a1cc4e2d3af2a20ab75e327b9de6c7f874fb9c458e2abd16b353a3500a5fee8389c5cf652b35b7f893e188b908fd2001ffc273a3754955b76d6d17000d71c4b286eff31128bb14bb42d3e843dc484950d25924c2f7e02a9384df46600814f896636bb4e6a36cf8f89f4612e5532297a08edea11e7ec429ccb31f297009f1e4906567108f4d5b29f32d6adb00c93216e7dd15a5145590195e3825f01000b0d13cdb9b7e15434c3556e8f6b66d760cb922d98a6bb4b745529fd0923da008adcedabe4abd30ca40ca5799d5f1accb99932237b8dd726339a1ff9b67224004d5a060d9a984c0e38182ac66725bb4c032f62a4257da4c249f7b5a63c4cee007ff8b7078c27f9dbfdaf72a7e7303904cf918f1add80e44b0b3f3c6302b95a006bc793ee99516bec68816f6b8148a250bd91ba15ace66c1ae0b5f2a86aac9d003b6894d9a43f83141fad6a4455aa8240afa83d20a5cafa12db7a8adba40d5200910ed68aa87b6b525dab8a12e8544b0b79a92e1fa03da6c4401ee2835b531700967e59a694d62c6cf4d9639e3325cecb8a7c23127f5c9a9bfb9ec99806fa90005733a58604eec934d78ec4d5f5b3fa1c5243f55c4c5431cbf7c819c2c8158a00ab9242fc43d534cf42d22c5b8482edab942c16fbf0457becba15ec4c9ecd8b00f849ee5eed64f7d35ec13a6e203bd428f1985b326bf3558fc5cafd66c433b3007dfeab587d55b8523568105d368aa2c635c2dae8b45809ea7c06aaa6f953fd005c26fe8d928191dff28dad3d24f8c6a74178d94260e8b22c3f60ead7ce46740019f8edeccb584c3df2d1f24898fc2f50b45b830b4792a51f906723f024b2890002cdf0328766f63c0b475e3259b948f1e8d2146d71562a94e2bc310f115ad7009b4edf2c7bac8a201f17a57d035eb91c1ad35c1e71802c923594806824c63800e36bc59c18ceba90e8cfe10a5590d895c4d444a26a4aa8ef4042a2e99e4c7c0040e67efb6d0fe472a1758d9851df167b4f7251a4840fbaf9cac2f408ce9ce2005402748ed6ce6cf8dc4ccdca375bff62fd7a064a87768fc1ac8d401243a6fd00883cccc2c4680120904d0429313c33e957975902d722715da82b3946ef68a30035a1fde364e33bbfd3eae2196e49e1e1c526f8ccf4b69c82cea3c9fb4718cf0098aebc0943bcca10ca4d437087e0ee6397897244aaa0b8f65557ca0e3065f800a70f9c860664eb9b174022111e8f616f3878d12cbd33fc8a95bf32cba61adc0022534cbe79ee787e4222fd9ee88bf8773759f2790adb1aa329c8d40a86486c00370b6b7639f62e0fa2442a0789bd7ab68d0fb8a513f7610c9b1f86aec2c69400bb9b6385795cb5c5ef0b6d3bb380dde151f145ac2b48407428f8ae22c42b990038e19b39b5cfab5ba18c46e2b6649076d201241f84fde908632f51e06fbf91008ded2c33304772f02eb3a17d96ecd6bc65eb345c8556fd836324f6cba2274200efd29a3eb4dc62584eb22c0fcd844f4356c1aaa195337b43d66ad9cb63417300991cca5bbb49e8629127c65934eacbeebacdd6366bc961f756739e4f244d250068ba3b515df2c6cd8a4569e8b88274c13299eab0473d50fbcc9ff8448e02f900eb7ef67fc6052642000da288fa0c32b5aead0902694285d2c6e0bd1db7c0c400bcf42aab66667dc217ab2316fb548f76082647257e3e4bf2a7a5efd95334500044b8cf02067517c08d27b988a4868167a18f877528b8e47096284a22fe916b00f4a34eaff4c56c5defb489d2b98af68f4a70c6444d799be60af1a5732bd218006731dda9a58ea143fbcbe039f86365daf306370d5f0940de86acbe37f9919800933dbf8e0188d11fb5327d07608ccfa9496a660f832ec3a771dc5ee2b9375e00e49c3aaf628eecdd85bab14be0d6b6281c1dfb8d5e06344ad01a5477ea1b5600d480d196781b488dba46d84b17cab118aa0d84c67f6235457d288a9b514d3800343df2d9b743fd04185f069300efd6d8893eb6587aca4af08d952a29ebea840054f634b8e480295b06aee4b55dabaa08cc25de53e1420456360aeb2f59c993004460c784ef22a1b6d68d6aac13ff169e80b6f261000d059db9eac80a5793ff004edc7f964ebcc411e5a69345d1e5b2fc9603cdb61f5c1e54b311a5dbc97f480095f2b9db41422fa42ac5b34160ca35f61445ee1b7026dbb75e933937e670e8003e798e184df2164eddddbc1b96b810cfe58757ea0ac53c3c038275f52261960028add582f27fbae169c9e97c7ee454356aafe21670c79b47652c69adb374bd00b9f2709b6597e0e7b9ddb89f2582e6ed2104d5f644d8eff95934abe28e6b3500cf94076ba1d6d842df855e71c7e592935e8d98174e95a9b8b330f04cf1b38d00cb3c3f933a76901586b6be9d0da962e3a0e8ef1f63c2a4e32e87712e925c2400ecff096aa5ae2c7856e3a97b74c688bd24730c8cdf9a1dbb5d286b99d29bd8009a8a09313658cd965e823fb986766e2322a9cd5038d45c802cda07088757b800de4d2b58d2d4f666b67ce5264a65ee7de77a07ad9be2a866a46c0ac775f0be00d466887f1e98d6877104afb9ff1fdf517ba6b149753fa30ceaaf85f61f83a9004c254c1a7da0e2a82c2cdb90587e95cdc3f05c9d1f0810de2719ec0564955a00349dd4946d204c4aa1e8d89a4378ae3882817697edf3bffd0b256b5b3dbb53004708971d3f04fdc85f9c620e804bec09edea7ca3439ffb16a09948a420bd5800b0b8d5d3adb91edd308928794c8deccf27f738b5883dfeff0591f0984c9f1f008c8bd8a10ceb3420adcf89496e6fee83c78c98f13d7731f4e413d2b96e8a0c00a32330d871aa72bbf906259ce82af22342b6f0c1679d0b987fd3a7edbc3260001964acf839edd9b8f1c298dfc21515b7023f3c9a1503c9400123d974a95f9600946fb127386693f210b9fcd4825bb6d22e15f07b8d0ab36dcaf51aa66e163b006d2c33c77d2a262edf33819b7b67197f3d0b13446d217cb7934e649934052c00a12fe5940c924353050045bad52151ce4d977a4f5cd592987df4aa39e6bdb300ba479f2119817345da5aadfd7253e2d062e127bcf3427609662d90c4ebf40a003a7af9739d194a0c2cd3188c1074b0d912cef14d03be03f842c2dc9d9499bd00f47b5e9783356e0666698cbd2b6202f06ae1f491caf3e20f97de7e85dfa70d0016b97a28abc3c7d2f2edf0740e9d53aa65a6fe32defa37eb7179e82fef41300047af1e6d57c00a39ccbc0ce30ae133b94172461e7158091ad13261074e93c30057360db1401f82b3ba58438bc7b007662994ef119555a1c1a35253047e545d0044b2720614f9584a3b325b724070b5df31e3b4aa714b837597ac0f39344003000403d4048d40d109ac7c50eb880151747c6d72cc8edc7537530470adc6077100f68c260a1abd15de19c3bfd9b609fbbac368ce7e5560af54d4a189797a44f800c339a184669197de603079e37bf8f38bd1b58a0be6b30cc132dbf153368034007b2be55ad56d28beebb3673c62d5db2e5cbb344357a6089af26fc7408407830037232590580117da4634cadf60a270701142762195755285150c4078717ad2001a0cc237b108d65a77a9f46c45ed779920503ed674fdf3b4560af7ee324ff4005cb8643f4d540673e9b7084492fcf6129436655eb95a6c285145e7f8e761b1008f1ebe15c23b6dda8cc5901dc371a406a6b6fe3a380b118e7b49349e97ba47002f4e8468ece9b6f957bbfa8f766f4d6968a19029ccd90b41e85125bfbb188b00cfcb71e04bf637631e3652b789ecb0016f53bd28bace21f4b5f1af840a048d00234c40dccbfedb33ab1ff829e9e6baa27ec22766f7a413b4d43493e9ba121300a5a8a501059a1f758b347c24259a2a87dd6e5cda916d3cf73f56b2e37bf245009a1dee1f2b0c75d7d4be09a74d8321314092e7ac345114b65425a16d7a958600d73bb48a895422d2a46f7367be261e95aaef79fd93656dbdaad753853f77660099654effc9a8a2cd4c446c29a1cb8711521f9ed35b288017c137df41efad0700274b306b00240e7aa8325f8c4056669ded620617b4a0e8f43b0d9591d2ca8800fd4c275a5e33ba9d43b13be2a658d329de2ab0797bda6f30e02551e06a2b2a003e05ac1faf05999568e424cd96be3b04ba0cd1b6d7181e6fee0869be7fb50f0025e8f340cb8a348f87c57bdbc6bc4f16a40493b16eafe658fec83b19945d1500706c98ce3678502275eeb03f530f3045895350add869c8b6b55b4f2cb8c28100fbbc3a404ca5c092e87e7f4af1cf2bfe2605be56188bb5852f67c72002c3010068e439edcee9ebe3c44adb33abd8e22bee17fc3d92cc53f145f9530898cf1b00b5d0dccec1d190154038a79f85fc5d1f481390a0842a4202ec3334761b88e60009019b6438988ac49df604d7c3d4e348a4b909459224ab2e2d48f5c519128c0033d3ba8ab633655a2b831126b15a9211f9f31c11d9ccd677de5c170ed82b3000e927413b7e713a7b06e1828dc289fe94a92e7eed47505cf38eb4461dd5924800e21a467685f9416044b22ee3202edcd22cabaf004a5a6a130a5434189c0ea500ac098a5ef07e49db9c32881b42298c0e80717b7adfc4bcdfe053bb0c03d9ef00d7a2157736fe4d7d30ad8c90941c720434e5f07e071541bcba5cb0a3b2a15b00cd43103d83301d53bbfff78315b767c906ed75a7b2834378d90279cfee389f00a571e306881a9b2060b518beb387f2846c5489cfd433f65e703da370899770009fda450afa04e6b6f3cf2236d4f93ef09600b0f865eca085058d219813635f00b05d7f18796163d29ff29baaa851aae790e6003438913777a1cad238a6cacb00faba470e1b979b615ccec70e36f9baf1f862d8e63c19e008a6db383f0e191a0058d1b950e20b4278c4e0ef002d1c8ce47131cd1fd2f62fe5e0cc40d39ae9180010689e1c0f7be5da98ac958069ea964fcfe4618b276bf6680eb2d67238526700818273b0d7201010c3032b115811380f258306e8caff67bd077ba71884cc4c008e51d8b6a541389166bdae962acfff3c844d6101c5e19c5dff13817ebea04200dd1555bfaae3dca06904ba0976eb6f5a63f3457d16282ab5050285dc67d73f0083a399b353a2f68f066377d8a8caee8cd6e00e969bb0c78c3dd41b2c377b2900e65e8df8da625835ab5fef1a23a40dc6cdbaf70ff6ffe482d35d7c6d3037b300d25dbac602dab9b916be10ee993f1b05a70781a39023e9b91809602eefeec1004cca3978f35b9d10abe1597dbb390c4fbdd9a7c95620a331ee29bf78f2465e0048e0e605ff8017c11eed66ce97e30d5a2c8646a3edf2812c65e1f5419da340007e507f81d6361a6d9f0e69fb3b6af11337cf29b6a65075c650facca337413800cb306112b876a6f95c57a711f306a5cde8194f254d9eb2887bbe81a1bc0be70095ffc10c210d0143b2c6e93333e0dac005986de4246efc8cea6394a59ab96800775d4dc0f5bd9c45026250bd5179de9dc168008968983be12ce365b68c9d6300bf2c3c31eb73c1147f2c66e1a4f41880d070f716d1a3594d68d7a05612676c00dfd713b124c7ac6645a497348f380d684587ee9921340902f91fbaf17ce2b6001592d65b890f403b4f944af6fe926cd503d20698056108215fe53f4746b30800a2fd7d1a1ce807648933a17c73854b67849f28be3682cefcbc1e8579f809b0002810e6c11739f91899706788ebe4b3a75d940a39b83ae84d9e68141006ee110005620b9cb7ba87e24c761a6a06565fd4fdbdfaa514094c03a83cf51e85f8e5008ace483b2ed6f8a3c93782b60df7538b407a3400eee6dbb50224b7d60a16b6006d3c50de8eab5ced0af1b77e3b2837df5511acb195984f0a313d682ba69591001a8b8a82829ca348aa1875d7c6d69e6af1c9b6017c34490a6446cf2dd615d5007261686a4a6b413a573e9c58273447ffcf51cc51c9a742c9bfa1e2159a36bf00618a6522d65bcd5e6deced4ec84930d8c7b45b2ca53d8d359d55578de1486000ccf9caf061d045fffdb4360eee0ac680bf41472b452a68cfada08776929daf0085f1af3ef1a1b68e76c12b0f1bdbcacde63ae1350739c7476488ce1c6a4b60006e193b301c3ef41006aafc984b259ae2e5752781e6d938b36726e6a17fc7d30028e3654e3b03f4e40314aa8c620430cfc64ad304339d41b6532f1465f6016f00417a9b9afe79f2c5a0d43aa7ecf02c951f4f0d056ae884c1faa712aa1899500041ef996e98c445c372d9d011aee70ad9199bb7535b96a4ee98c90d7a9b652b005dcd356cc2507a1394f7bc63780f114c124128cd7ff8da4f38a130878844cb001cbc542c51725cf75b5a870ac356801543d12e062c2ad31e8cec0ce3b0c7460023141cb000b1ccaf37d8c3f3c5aa4e806b3d31be5fdede985f098753a03fd000836e0399e6df4726a241325e0a822f10e1e64b13d6f9800183e4c528f98ff600ae07ad9dc820337da10d75a95f99c833fecad0d50d0d65ba3ca06724f138df00902c48645fd26d6fa796f1bcee4eb96c9e50f1eac6016195980eeef05ba29300f6fe605ffdbe5e08468406c4cb54209548b05084dbdc0e31b8a0510ea0407d007bbd4fcbbdc65e605a068008678016da56dd85f721812c9111137a1dd5a4d2002fb29cee323b6d501da19265851a100cbf6071955b68fef650144ae5e6ee1500dfe9915f16cd90cb9b37ebc586494ad354061401b2420eef74a109acf96d3e00f8ee76d133840f9844b3aa0bfbef539d8d5f745f78400c6948f03fe7728c5b005a7ff27dd69508428d7e39cce9345264d38c9dd34296789d0271b62d8ffbc60047b8590102c8fcc34ab1e42a6c94725bb89fddc3589961c9dc90a0c383fe51002109927037c1be19ebc30f2f5b34676cf6413782f045b08ee8b58b53ff2229002165d12316c03024e8f8cdb7530d4ca6909d07bc86f44699fe7083c0c1b52100d8f844db2070d43261e8716234fb22ebbbea517549cc8fe6aed7978c35ba0200a9d54e9cd6adf57624306e8d2203e386cd75d5b06d18f7b1ae28586e5eec2200e4fdba7f7f98cc0a4def6604f8dfc88d36b6aeda49a79c3807994c91a85ee500e8cdf24d18aeed454cd877ec3924518982a915534af07d531bb94a74fd30350065561be52cef7555d5c3432eecb1ef3ee80a1ddba7a70fee7e200a6004951600fc697792a1400de4dcc2834c9bd86bf44f074733892f8c539ed2b53bff687e00a2796ae8fce84fe9651cd996c3c2a118b170a70aabf24befb5724b0dd432c700badb2dd77f8db2e5fbedc9299d1e144d95992615c27b1c7bd7b0a18df7731e00eca00e5d780fae7f886bc33544dc2e799f9cec10a2d787d15afaae756ff57e006cf7d0a1b5071418f4418575eb711cd088576a8c2975a43b223af0bb4c150a00dab1955c697d7afffa67b163c5f1e98d804de6cc875bb4a65fd444e66ec29e001097eb7b0a8c977f8ee4e0d25f94705217cc8032abe14eedee0ceaa670371b00b65d0a42a11502a7912dc0c2820639356cf7db1b9ae0d4d8b65d8dd738d53a00472179a59612fe2ca665ad6428245a9fc06d3de9a7d3f94a1269db73acb7400044d041720a3d10952a6d6bc5d0f9e5a2f9123eafe04c38ba4db24d90aadee100e55012aaf9c60b6e019da5cc6f69f3c2b2a5d8fd6c0903fcfa3b68073c410c009f1628efdad0382a211ceb301c17d5757e512e073fbd85e8538dda04a7962600944b72920cb9848b1784fc9e815c78f95f515daf9d6d906cd353aff2138924002eb4a038354040ec06059bee79abe4b056fcb9f7e5128fbd81e806088e19830099b250562478363d5b45bec5f648a52a33a518b35f8075bfeda18e0bfa207300d8eb4b5cc24fa59ba60aa33b1ac1a27e2bf34230361901f714a2f58ea475a200ad93422e02c1b881c6ae1e40db5fd1b3c9efc00ac0f156610967e83d5806590092b2e72072533fcc2307d988085ca6da654c04ffc67dfae21a984c0b5a9e3e00f2bdcd45050a9c0983a78e8ee94eb9625df93b12d8416460ac00c0c0c0a0110003ef9d5e316eda01d5b6d0b951d3124384a56e4056bf7ad24d45978bb86dc200745541bec163f5d3806bf7b758d45bb3846854367514f817b54796747f2b1b00a6907bb5250d3bc72ac51bb61bf6f6bcce9623a2487b229df393db4af9185700724835094b79cc15b40ca170cc0d1064317472b22ccc161ff9eb7793d45ee400ff3a057ede4fb86e53ad891bbb6dfe3c1598dad1cffef4843dac37402bf4ac00a02d1953077429b18f2a66482527f32f2e566217c08d991ae8624b9530967400e7d9350f3268221659b3f4fe4fbfdc8abaff20c3fcabfa9c8f5d9d004d55ed00dd68b9ad051aaf51322633df92610638c5de49b85cef9d2794d6545bc5ca5e000652a7e1caf518ae7988f0ea520364c2639857f91b92e4e3ba410935625ab200a260cfe2a8aab46b0c0a0a3d3ac232e4db625ebd51e375facbe7528a0222ef0052e9e94ca176d50b7b39d97624f86b93b1f551ddd4716e35033e7dddf33812009c097328e8da7794c4f98222bda0e3eb595d0f83ab97dc84eeba950f6c14ee00e6409e797c6f20880db8fce5f1c1840a318b537132831d185f7a706d799fcf0026266cf744990a3b831ffeba6ff6063a6442a7b7de104ebc43e4b4004c5fc700ac8b89401ded475a1b376df494b8e53171ae6e7c58df93e995ae608871b22000a1d74c12c417c08721cc65b2fda424b13faafdd5c482a6597b1fa5712ed9b80022e7a6a9bd291867bafa4353e737429620e38472c297ba791a079dddbd2d4b009eb6ae11203f2be8930abfa2af17f4c9bb1e330751f4db1a3cfe590e6c72d500e8b654a2ee865591c9684e298667606cf6b999958d291c166300c32900e4ce00d0459343d96bf44e9ecb5c2ff2fa6843f13d32d7a4189a36858e68a6f4741a0046272452124958d6cfae13248232faa3f96a9f1e56abfcc07b34a1d50300e600e985613fd7750ac33b3605a1bab4ef99f2943ad07b0bde7228b288b9d06b5400d5d1f53e19792271173fa173dc029f6ec998d0580903a97572ba35d43218d70095efe594184108088e32bf8e81caf5c6c9e4c5d8b9611ac6caaba135e202e8003b01fa8e433f598dfe432ea62f0d8d8c9e68fc0752ccd51f99b50b9869788000525b09dcc52b7c6c9e75dd73403fd9b59f61e04b0e2c4cb898070d035dc887002b96f5e49f1d27cbe43cec55b383af7a7eb2873d19b5da660a92ae4bf9752e00bd66d43d1cb49d3b89e9cc75eb960ff7da20f66cbec2be268fac1d5d1c17d100f52f6a1149c119377191ec72da12c59be8b92d847e78ffa43fb59a80793358000f0b3519cf5bbcdcca2cf4b63d6ae24f8773bc3b4f1d50bd93723a19e2281e0085517b86305232f41a72202cf48360659821b35c1f791b62e2d951ad0ea17900c09d6e4426cd6c9053a0e03c7c0207d82a1316d8559333caad0da02e72b5510090deeb9250d68681d34e533a35f8fc64f0364bcdfff6852483b762d4b4b114009ce276cb279cb8bc3bbb333e8b842fa2789cd3eb18a6f188d8bfbdb041cf50006b8fa3418440c70a5610dbe83c6e5bdca02baeec69af4653454e119bf3381b00b60fd32bd5289823d7f1b159898aa6b4bded3b4cbdc2ac768db042d52d0d960003e65188eed31bc4f958b1e8ce40fba5c3f67e4ede309f0f816ce016bf29df0071b6e2d2924507735b82c962f02ef716d08db15af8b6a8edadbdaae867024a0026274edd8ac3e9b12fe273201f4a1a93ab3fe056df6022d2af3563e3209f3400b26b41bb2fdb15d8f13193c042ac6cfc627695b0b5c1a681c23c79ff20936300e3b4be62e2bec0d3e4be865c0f24a3a1bb512f76020b3ab4cf638ac510781600bc3647ead08fc37523daa74a4ecc1e0a84e2f86868abd0c6bc4062fe99b4790030d5db5f96a57571fc0019126608b91a5992a51676d22f3b544921a5b0a56f00d39dd6049c39230d32c1d52db662733140cc54b3b0a198b47a787c4776545900061baadb65bcb4fb51e9352af4729bda4529136ddc4569486fa947b32a1db500961cf6c5c24d9cec72459a2e6a62cbb8027f0dfafb5c57820e144e47db9adb0089d800558406c230475e7523d0c1d965f3d6bf83360416d2c3e2f024bec5be00c0c9a753d6d8f7b8b085da3011ef5b893387b7cfaa9bc3819eeb6a5112158a0043d5334bbbd4a88a5b5d37d5e0466ec5469f58fa23ea9816bf8891f408469d00c136c72242c494faa3f509adb2c7e9718e4c0c0022f8e75afba24447f22a3500f8992efb5ae0b2e6beab663534ecb37b91d8190765aac1f8559e804995f4360012104b4cdb199b62d4fee078ac7f63eae8e0faa665e1a07ff9f3a338fde69900aa3efe100bc1a6dac3fa6c05878382a27383f126d32818d77bfcbf9e4b7448007a18da17f056e9f09f7b1acef1e78062cb6bc483ce53c7153ed9a99c137198007d406f4a20f6ae041a64ede5acd07c7845619a596aa62e61180a120c7fc4570000dab0bf5c9642b79d776ddca83e52f2ed436aaad4aaa9a90526e55e6b6147009b7b720184cc5635b7ecdb2a793aa37eb54c6e7b8d9f43a37e3796a07fcde10066c991394818aff9441b726601ce8b2d854402e0cee76f51edb03787a781e9007e10caa0d96aa414f1a70118980d8774631c10b77d208077d493a64ed71e020065ae1ea7ed0f6ee1ca2b5525e1a3af42a5bb5ad4eee659c61e7f0c24c8684100385692579385976213352189c57528ac6f068005ea7eff15c888a69e279df00069d860b6207d66d2a4608934bd9d99e9248736ec9c294ae29e95192c73a0be000d3794cf7a286001b3da2fb34775f2aa21f9a5abfacd5c4068086af8fb8a6d00ca7b234f6676eba22a90303a8dcfa84cd2b1c55844e3bf49a034b7ad228d0d00cc312907a868883e3cffa87ec278a75c3b89cd15924b5780560bf3b48af4cd005060bba413171bceaf6881333f2495023a000db49dbcb73177b4415bdd32da00c3a575ddd73745a8b873cc59cdf322284c85c7f82f5d5af86b13e9b85d519b00e9929db9322200dc8be76afef0a7136334dd67b838f782764b943d9407bd1b006fe8faddba8de94a050c1a48dd066a71d25c1375bb58c388ff6923a15fb5d300e64861f02aae64508958cc9618b90c4d20bbc63425dd3c5dde2ff4576a4f7500a60b3e81b4e5349a3ba6f6384efc6d050fb7949c33e0813d8723b4cd905376003ce43ed3684fff19d11e370ee015b63ebdf853aa63959cd3e4112282b0cba600c355207b05ad8b62c2bbd8ae7de654c8ded1f7c6793195b19bacadc75e919b009cdbae2271320726c51e26e7d8af27f9be590bdeb4ebc80bcd2f3ba114072c00ef01032ef34af40ad1dfb5ac819dcb8b3cede29040fd3327b20c4dd46be4c600413bc490e6febe3f90013409b239932c77011e7573bddbd98aeaee3f9f761b006f04e85c8ff5fd2c1dd54e9562d2866cf27cd96157a5df8ccd932e7a7be79f00576b52fcd5bc04dcc9e38a9fd319bcca8f9c32330e319e26dcdc14a970103f003c87c80544aa4e30f0f56f86920ab2c7c5ef25f2d86d81bd82e9f7c1f203340028e0c3dbdb0bd6a8d2efbb2f780dfdf7c8b0504aebaf76f1839d2ca29f8b8700f221213cf5762b77d9c3d339410769783d234f548f16fabb34f37872e043d1000a126cfe4819536e2dae816941a77efbb87f08f01b3e01420b7ef5e8382e6e0023a82853c4a667b128d275955a9a5233ebbaadd39bab742a293c079a16ac990043292e913e8c58e769b4c9824ded7d6906204ef01fe1485a40da55c79c428d002518d37dd877186e978c220a9e810a27e14142a6e8e446e0e9f8892e13442e003824824339771440df455bbff4836e8fccb30a45b7715d42d9e3e75b5bfbe300112aff1a72c6c7b3ff9e80df018dba9f745b249207c7e03b4541e56ac794db0088eb305da7958e93220d9f04004b851c2b509de9ff8ec52046a8642642b5b5007d50e5c16c23eb96356ee169ab28f1ac51289d9d8175610866a9a7873d245e00296d98dbc6117537b5657bb29241ef591c5d7c470c6a83328505355c7e9c50003a1190ea21956c3b99b1a1731d351dc0f15800d44eaeedef677294e6a0805c009d7e212a30bc3891beb15f6d33fedf34835c362a0d1f0d3d438d52f43a9197000d785726159ed32d2fbff40d0368252930d9b56ac2b6dcef333de39f890da4001a06b84c7fe6eadce9a3d6f61f5f0fc8231d313a0f0e64e833da3972f1e1b5002cf1819ea7a5e0f7fc486b529d89b9ad9e6fb80e1eb00a699995982962a22e001eb8bc24c86e3a5275a659ee5a7d4e0b3ae590a517e603fa89c18211a1d8da00f23b5290f0bf5b46047bba17f8a2ac2db1a31de1384dd91b009f0d8baa2d310036ba25e6ba04132ded5cf32a651e5945db0a6b34fe19c383a64ce78492baac00becf3118df309e0f99e4480443335d1c1ed5bef576fd1f16fb64b5c78e678000c4c4afa359f807acc34193e4cbd7777f0aacc0965aad67ab712a133e8e38e70025cf0753abc13094af017da915e27826d1c99a76c0858332810b6a01a4f93e0094ad4a7b15342c45d684b6bc1251c6ed6ce8e50bef3f57828d059f7637440c00fa1eee68a4b3453555954e6c96a9f6fc5bb1fa915e654dfdc9e120d8a960720071795eebc73ab34cddd3a3bc3064eabb4263e4529375fee62351466e6eac1e003e454273b22d827ff671f8f1ec21cfef3b0e11368bcf2250ccdaf80df9b26b00da4f9fe45f25e311ffeac5a05a04cbabb76cc0acd56d37aef95c426774c5bd00d0fc2a89f9bb099d6f3fbd8e2d0f6746044141ddac4cfce07853b1d0caf5e1000a24ccc9da47d5256ab4a69c364c0c62ca9914458df4a2f0fab2f150a95ce50008b0a7cc0d4182248caabeb554afcd9237ab065d0d10e92999aaec0277bb1200fb955624ff6c6c2097c7d40e5012b4b21520fbdbd833b4bd9e3e1023fa473500729e5b1f0820278d6da27e3bee52d7ec2bbcdc07e4400cfe8e13abfe4d164d005b40c49ae6b908550b485de397a01904413e8328fb7d54c1a69c1cafc73eb7001497ee9964546aca48b717a4e80a341679b9d63379c60302c4cecc10d3467100776a1f057fb6207f75f4e915183812529a23be8a871340fe1c204c2b2086ff002a1e1a739a0f392bfc2cc544966ef0223c68d120d6bda162bddb8e8dc5aa0f00ca33f242e47f51594d30f25d185cce3192813929ec3a9eda9842b1e488e35f00cfcf2030bf4817fed2d9dfa8e650b73f5ed46886175548496e3d21c43d266d00d8d5d02fa4d6289ddb1363df47d72e55c387869482794424ab718d335fd3d900ec9e3bb43e50f33014118f0ccd7ec246bf0ec27bef5eb9345cb50c92fb256b001d2b2530bcffb63a1294aafab05964ec6e065f961c486fff6b7d4d3e4f539c006e1f05f4e6713367d78c894a9c6cd767530d3800370aee989bab42fddb4f300099f8dbac41a05d1142d38dcb439be8a94cfd2f5a89c3fafe0e5da859d46f78005a59202c0e0d40fa15e1c36248f23b953e19ba53fdab5ca0c6a41161ed9cc6005023a9aba4c87b646541912fc7f1087fbaaecc2ea978bc2dd00ffa65a410c0006bd087495a8a8f70ba2d0e6a463f1ef0c372707e0702c29820157c66f1b401003e5b571e48714ad403be51aeef3c2a359e01ddebbc85960e8d037f7a133b84001abb970b9fc2f02e3f6c91a935afef22de2fe46c13d9702e263a63333b38e7008acd16e4e40e39ef98072d99600bfe9a86d80a738b8b7de1b6fb59691905490031f6960f05b859461d39e91d08854baaad0e5e78c2b27b8d520a61f4eaf5a0001cd4fb26cd93dfe0f73fdfda0a5f2542410ba40a7631b2ed624c8d73721aee00fb6fb41ec68deaa90a2a34610bc97cc46c0dd372e4491d42b1f634c15678460098a8c71e3b25bec493cbea5834489c9db4fce32d1c0c452bc042f7d56af95400c14b52070a09fd5bed5bc90595fab97531ada6ac9db6120d4c5d253db9e1a90061bddee82bc9a663a675043a72a03d569e08f83beec3c2c07929b6b4fc26f700513ebf1d67c85cf43a96e15dba2b742d3f70941659499e0fd18ad98f1f613c00aaa82b75d5b900c3f0c35e2263884c3f913ff21703446b589490ce68d810f500748d03655ec5a012fb27dd3fa743e4d5d3192ad6e774e83e6bfb072ce9cdd600d58b4f501c26738b4e4053efbe18466c960703fb7c247ada1dcc71e0dac1a300eb4b1359aab0e7fbac93ef7a9c82b3d35702900f7fdbebef662cc2901232a200c7c53171cdcf2f0ffd11362a4217b25dfcf6bd1339ad7e6e3481bf4ccbd24500bbb3f7ee513f6143323902ae9e7679098426f71c0d15def84904b836ca17e200b4e278088093ec12398fd8c6f002f3fd4aed201b2d4f7da845b654411c3c7d0079ab6fef4bfa73a9199ca5d1f30f746d667a01e35a034e2b10c40ba507ac1c009cd2bfd92839f12390dbf3abf7eef89a80f05644d2721f5020ab6573e2382e0070b1a51182163235c342711c76831c32253273d85fe1ca405dbeedb7bcc3510048f84552cccc0110956c6ac2b60a5eef2e51edc60c14abb2580846c5b1ff0200e38afd9040799773b7e1db9a5b97649a921ab33c5b7d56eb28147d9bbc7553007b31809febe932baea64af37672360ba7474e3c081136f0dcba219721a3fbe00b2df2d23d73badcdc3eb8b89c5620fd19da881ee1c57deecb2ea0779ff694d007d6c29990cda595db7d43f1dcd4f0475cb480a0ff0232c6917f83df4ea3d2000ae64efe69bd5d5b15a2eaf4add2dd12e03154ec664985069f62b0cc52f230000296dcaedc023e7a8ed63421dacebd54ffd1163a476e3182b3b5bf19eadcc9d00a04f57419c904f1f3abfd03e8ba517284ba46564227a073311f03a9e92bfb80084705cdbeed90a87ee4740b4115642a1f4b83ef5bbef7a14123045cc945be200f86943720c2bdaf238275bb3c1c38f50298af851bd2d39a3dcbbdb28d0b3f200de9d131eba236c4de857d16522b31ee9ecf10b5caa683cdfa34199f427334e0016a3e0781cf70768f94e96a55343e7deee49b5644f9b539a778e7dd4b25eaa00b6af33563e277ceedbef29391c213de78d8637a98a384463a095d14e7e2455001c9a0ccd1a46c635ef32fc88b7829b4245c024eecc3322cee717d34a31f6bd00e63cd5725e77811d664a0ccf98b04968778437a611f4816f1c0956ca18210a00dc5c9cf54cf53ae382eeb74dc207260f7748e109449c6df071b353fafccbcf0064369c358ad58532d57cc00acfb1aad1a03d4c6a418a0f0aeefc2d64b88c7200a7a53775c4a99dbbbc1016a605f596dcedd7a2defa01e132f6e279a20215e700a78def9cd7c282486df682a4c1a25d9e315d6286b40ec489a05e79ef4f0ac500757d34a97eb13c597352b5e5d73d821195d6f03d73f36072fc1b8a2aeb0d52005ed3e3ac6f515c531513f89b96c8aa2b409b6180a20c54a54fd45debc3d5ee007d87198ced65d6fd454d1c993c244e742f46e99ec1600d9ef8531d879d9d1300177b905543187667decb3c7977b40c2b367e8c66944eddcea941f771710c7f002ea99f98a18cb3b0d8c7fa95231b647fb46b439ac5e58d469606c9ef15726800a238f0ef8feb41befc844badfc13c8737a7e6fac8ce6f73005fc4afb11f29e00b6b3f4e14726e000d57c6f90e8397b1857a35d52f7f6882da9212adffba30400ab611f01e8a55d80f700b59fc518f02751673a270290cf4418770e1ebc0620003cffb14372ebbfddfe0efbf474a6313c624b02dbac81dc78ed8329f4184b44007a77b46c47dfbeeec62efe771cee510f4b4d643437c50d4f0df783a5bbb0910077cbefa9e01081a34c2236870903b0e51abcdc436e305053bd2fe9984d8e9600d3ab17af7c1208d4360f7555f2ee4c4104719095c0f0693585c6e2ea3215ca007260310fc5984da7c8f1222f19e9c5de6b69789de49c2bbe2fe665b58399d7006beb7654d2232bd2f0508ebeccf13fa68523428ae8ae96849b75c054b39b7400705989903b045bc8896eda0bfde0b030ca66c686cd585e8a529a3799f990a7004a9f801aa546f1ec14a9b2113353d758cbb4134c5d43470ca676716671655f001b658a4107673b2d1e0b5ad4fc56fbf8b7403574d05d9e275909473140ed9b00d03cd10ac5e3412443643ef9309471cd7f83f71235d0424799ff4235408ae800faf36bab64f36ff7305c54abe5e4a5d6c567d62e95572ecedcf36e30d481f500b9591c5042bc486659eed5f735b95910abe23844d07732dcd4de32b5d66c2200e4ee93d6b029c6602d4e0d8af0465061c21b720d92c8223061078d0c6181e3001dde01d11b1e92d1092c41085fbf4ff6e90e7539b1db1e06db5557fbfdff8d0051b10f4251e78eddb93dcab18dfd1a24e7716773c86f9deb2194bb5a636fa500844d6557443fe38940315ddc1ffa7dd04f3dc86c35ff9ee1e3f6e0b2dc04c7004446e5d1ce0a141886708a382904242486651f33f3cb3e62112120af77fe8e00a5eb4e5cafd61205afeb12a927e8bba447bfa5bb9f9436dbb6281c0a123b7700db913dfc5d633488019b8903f063401295038d54d54317b28d90fa0f943a5400ac0c571242832cec6d9f9a4015f8e79437d621132098b0da832a06026c54490065be568b132e195c9a59811ad2cb1a52b0af87c3b84787bad801957ff1937500bf8c55a62d74d81f1cf76af322fe0cd2f86f7e22d2923350e3bf7e7863d9ac0058fc791bd1bd7450161765b3c718e8beb80d38ad9805791e979e0b7f12619f006a97d70f9f54b09c8ad6fee827aa3287fd3a57d2eca0430366db497657beed00f4886436f3b9ca85ca59ba40d35d2ab775c6cd70523a75137c9901ca9df337007125b04ea8d624cbbadbf569521be8c0165cb0d0c26e25196a8c966e762ef8002555aa9011f230a2b475187a45477bfd7c8aaa0ac39cb79ce189425f2a2bd90070c579fe5a4f1c5cb8860b97259a780ed561e2c4226e09cc7a740121ddf18b006d7c5957e3126e551dde78535a271dd2d4a32c72ffe037b7217b816bbe030e00acc5a7fd5839dad78c1e5031bd1391187ca9aa020ec4fc42063e198202e62300afdd6a36e5fd60bf3da3a2e00ca5405a4e97871822602db2677cbb60cbc8ab009293a187fa86a48181352489d773a308cf3697354131d3b60ff318409bc3fe007bc3501a1890e87a110540528386f496a0d94ac728df74653c2c0b14ce05440058189c7bab604a620ef77c7abab742b869aefc0cc61f18e67ef7d2a8e98272008f500236736d54f988054d0a5bdacb5cec7f78601f783c151931d48eac5c2b00e0c54d903eaf3f5e70e538fbcd5f2639800fb6affb5f1807f4132a3cda10a100f9b9a0b74684a5883e0ddd303a6885a900ccc23b41d1e50672083147d4741e0032f87fc45d58ecb29a6c2133d80218d018d01a8b8c84591b4a187b8a41387200bb6abb5083feda70ccadbf18cd485a6af3cf0d751fadb426336ca2a2051bc700d13dee71ea8c7f852bfb5483585d9dd294ac4ab98329efe9e47e04e494564d006b36ca25dd087ccc522a76d9b777c03fb8d36b16843cb53d066db33287cbc9004ffa2d9534fc137ebaab5e119dec2a49faa3632ce6d3723e1e49b7f4f0d3860070d55556cd6132435253b827aef6d0e72fe50e9aaccdab1ae562bd11fd91a600f67346efd3262f6f3cbe925ea84a474affb4e38902c2ab1fd5fbfd1eba4e010082d6bb08c645a782e6b48a4344b820a45d81e526c2fdd78a6ee1900eb2014e00a9a45fa46495f4d1248b916df48f70bda92f5ddfd5ff3da89b81c7c8f07b6900db0dc6ee504d70b7de56a4350f997cae494afaf57511f3548d36752beab9890060fd9e2bbc012986d6aef749e242607dae4b94316525612a7ab9b599071915003ec4105e00dad91369fc2b3fa80c34346777664bcc59c6a4f2f97cb2dcb64b0091362116ea3b8b48c12b2ad268170a76e71842bb3458064bf6246438301f3f003b0ddce4d2c49fe90e0da03bd796a7d1d19b4531cc4f9db7601a2a95423677007fbc3aa964d4616f3142ce2e6e9374fbc58c3921ee07129addbf68bf1cf695000a6330e88148374df3b07e4702e829f7ab1d87d735b3cabb3750e692c0a0ca006080b13df801c286cf6f2a684d0b48b761d69d5e21a07e0831213d0800e61200f5fe8536cb6fd8303ff333ff4b5180ffb19f95b40f1dbbf6c31ef497877f0400a9cf2531127317047e6a9c952cb878dfa005871f224d2325f924b92ce1564600785957ee33662f6a3fc88c768838dc57d1678eb6dcb7aca021da280f680cf4003f4051bd9a60afdeadbcbb297c841a22ddca4c866054e90ee28caa0ae02711008c0a00a61d73f30a2168bca29764d4e8fe9e4fe5cd9a7d68012a793b064b01006a701714549c4a93c4e7d189ee739d80ad5594904f087a43762f0b066cc52c006c98e626158c52fe3723fe085b27e2416e41d831f01a74f37b6047c54a2cf500f2770017459d554cb836817d4ec1cbc022296256b0995ecf2a8d7bde5fa9120044c637565535d844bf051787973d08f7022384ecac55343bf246185f603afe00685fadc30639d7b182ddd8148c0736b490d0ec401f8ca8b0a312d64ae1c32000b3b60eb4ced4c431286a9c5b12399fab8377b776498bc9d868144359553d05007e1fd6817e2fe7ea0a3a74fb53144131ec3b222a4461801a17f1b3ce1687840026124adc8440e83883facdef6ad29e407c266602db36c54391c3e3cca1348500e514d2859d6aadd5a69a4f20f3b0139e20b78f3ec80b7e9a725cf952a8513f0099271aabdbdf7fce9a4a78460aee57e8fb88fd4d4ec6e3e24c899aa63d8fcd007003402c6a1dc66a134730335d2f873bd03dbb8448190dd2763c22b33544de00cd09e96b4783d37cfa15bbccaf4e60059f77424f5f414bcd78d2f88270f850003f38afccd74bb12f3b44c666755ee217c1391e17760a54bb461fded5fdb31500c6fd8df0b5c4e6b4230e006ebb6ffa9f4e539c610f2269ed93043014ce6c3a000f75b85504dfa711e2b9604b77e67e6180246ef848ba684194e88bf118e5e900d1ed3951beef7b8ba44339b43650a82543705c00c1274838ef1c5e2d57e9fb0009e9406f8161cf6cb5908815dd4044dad871dd16e74cc846cb46294d3a5d6a000aa0915a25554755a4496fc82bb7575551870c40bf791a3462f57ac00911fd00dc129b7202977ab2943d18b734819a4662e73a3e0553c4d6b0778c92c3d53700470f101981290cae511f9d5ac933e7332f77d863f1e8e71e816e77f13e139800a93f6f034cbf1561cb8407296ec18d08a990b5b417a8ce29c14382ff6a670700c1c19f3bd73fa4bb6ff7d59c33fd0d65f2a38c3387321f9722410869ebeb7500419b9600235aa3134b56b12b35465a8a06e7b3d65688245ae843511336a3c8006dd4129bf4cf7b9ba7db1c8db0f3e30c49caba2647b7a0bbde5d25341c7e24009598f7828ffea13bd61d9c70bda8326840f54f0a8af4a4324d645774899caa006b7f1deda86885860722067b3345422f19f5b14532f434d706b8206b14b59b008803b6bc75bc7535cc11ffa18d25302a4289b1ca6d2b8df2419d0eaca3854d0099cc0ee0b97eadfda733dac3f74b985de651e8d4a77de5a8fd40291d997ed300c45bb1678883083b841167054be6d7ab27287c09df428621529bb57a9999730023dc259df72e55b4ff39e54376c589f91666409ba215e894ae1d50e480c3810000261855153d1ac83f2c8e951bc7722e0173c18695daa2b7946559ff44f686001c57c6e2ba7f3e194898e98b370ab55b253a775037dcb746efd638480aafe700ecf6e06f24026719e77707f7e36ebe42ed17be0afff2766f7f95be79d6ed680029057048be0005a8e46baa95f61f59d29379d7f5966b3f897115ff21be651b0065750277430c0968d4ae1beb8ddcb6ad63474b03897aee08c41314ae3e9f7e006f8922959464fc83e239183f7231f975b77ff7be4afd0ba6ec6eb91e56976400154b6f97e95897c930a9ce2fddbaac77c12ef4f623239e8aac4cda8bf9378000eadc5ecd0b8cf193571ac0aa789cb7ab0eb59049e6771f5b8f9b87efa4eacc002f449a41fe94647333b30a02b5320a3b4fc3ba05be18e701caed485d202d3700158e6ed5dafad276b1219e3e712bfc7de2ab1b5c91443081cef2cceff6c5eb0057096dfbe5437bbdcaea05ab6f7018c2e1a88faf13ea4e723d9d753d328858003eef5755f7dfe409627c8067df30775ba26de2b53e0f984f4f0be482b2794e009dd1fdab4bc2d034eb81827ff1bbe7b00bfc642aed11c3177edba01f0bd3d900ff3ffae4b4987f376b080d4271d3b831f44745134ffa8092e716cc5ef6face00e49b5bd5736c1d5430b186f9a2fc04590f8183aaa15680254843ca63d91cee00edba40fff4c4f226f77726f95f4427a5b3b7dfd5d1b8db39bbd183484a0498003af91d6ef2ea6bf3e6e2d9a74789cdb70bb30de35265506d62329a82117f1400e7811236cc9a4d7edfc1b38583e39c67aa50a645711209b1fc81c40095d3ce00bf1d79c026934f37a0fe47189468a1ede96302353120c6eb267ada189f6e26003b93dd370a2628e9761c0b215ec90359bb3479f1194bd37cfbcd3a77ddfe9c00e2465c6185bb5a069846b6c8f384e1896cacae10fe94f471c8b5fb559320ee007cbc6121429ad452ba0072077d029bf9da0315083e012740ead460531398ac0082c418ef26fda21e34b53e774537c9f414925e0156026e2e6724de4078cb9e00c51958606f8da99a295f73552961042bc230729f04872726c9ece810b42836001433df125fee8aa5768417bd3551105e450aa579facf0f634ee3b0a5b17ec10053320f69785af588d2346bd549f2195d2a4e0c6475e8f68bd88c2ac10aec8a00130245a91dbeb879928b86e195b704f90987e329cb12f0f7a588d56e9c52fb00d5332a97b0ac1e75fe0ae7774a9ea785dec3f35ef96274d0c66a23773569330046dc571524b280f30d3d1296c3f0d90b80f4cea8f4e0df672d028026164d5b002035a91d6047d24b6be03fcf7fb130d9a722dd4f62479429e197a74d7bff54001f9671e044384bd444daf2775a08ce318b6eb99381f610632da2ae19aff5b3009edb41f2300441e5d1ae39992f2ba747d40668879314f8edc1332a876ead8400e0b98508355a4234987575507b272540139d54235c08d0d49e75be63611e3a004df272f960c37782230f9cfa89dcaa9d7016f545bb382f5135c80264c6cf5c00a1c64d56abb19306f33ef22a6d6ca55b919ed9084cd4cecb01c426061c11eb007282a3514f6c700da6c8e247610e1c95816b457de09fb102487f836d9e53d000455eeffdfacb10c0707896248d73f8332cc2a2cf1a2b4541eb9c474b8b03dc00855c074354349f7d027daf9d537cf3a9cf6c1fc9a7f69b7781d671f8ab3754004061d3e3adfb7660de7d18bfcf1f32b30b5b020c79545b4b57cfc92a3d0c3e003b3981470eade70bb2e97c961718917f7d8cd78c2c77ac42a42cf220738a7800c009da89d59218f467ba07eb9cf5e71c4b922a124cec14f4e38638c9168fde00127e221d8ca500cab7e4d9284e43632c95b6a204b12c7a8e1d62e2a2bcb3db00a23e4235e2d16b7489ee4b5c7c2fdb2a85d69796a911ed26cf1e0ae80c75be00261ef445d434367424aabf6e7dc8db3a8473ed4955023caba97b29c9c3a2f900a3214a6088632f746b653af37db96d9e1a966d4ffc9afac0a046293482f50b007998434cd0ac32858855366607677b1f3fae24ee595eb6f6064cd5946c66c400a4be54a2f24b837e75f72369f1f0fcc664f3f7421acec889a413e3a3170b1d00cf278b610bb70bc104aafac1f2959717a902ba02e92f4dea669b2db6aae7be008d088412f6b527b40754501bc8e49ed26de9da156899f5dbcbd5745867eb4a008d13faab90312791a4047480491e74230997e632ecde6f1db51b79b47ad31a00d054c90a03b226ab6c74d4d36fcd3a77e0e8244343ffab08a0a866d477355400895819d7279112feb132ae8e2f8f934d34d0d39fdfe908991604b08602de1100e7238eec3510db5f8e9e850c4cbb2ad61851c7ea675e6b4354ef3c4edd09b400200020bbacb4793421deac326aceb7b0c711dbb3a1e400b4eca15991bd9a34000c5600513a2c1bddb9ef73b6618397406ae93471b511d253477cf61058be0300a1e11b255f75e00da2b3999c1aa214d9b4cd91e5621c5157861e6d6725dfb1004affa647c9e61812501326f66c002907061521a67db1173eb6a2cf62381ecc00ce8b40afcf7b58e41734070c1f4c8b849b49577d52b857138f248af0db44c60078ebdd7544a8c230efab88b4632252667a31255c9e8e03d4fe36f669142685004d4c43a0565a6b699e1f7cf485337dd10cff6d230981bc759245f51b944875003dc5edd55d706e4ea7b956dc960cd78968bcb7cda8723513e5f037f0b6919b0011dd23ea57726b2018947c6ff0bca7300f29579d1bfee10b86dad740b634fd0047f7504f8ebef43085f5514c799f26e959f295f698c48766405fe4a993c1ed002d3fe0b4bdf2e4c89a034903ee7f390b89e0a045f9b6de33fdc4d4794989cd009d7a3e94d0efaceed9218f0eeef87b42d63da8db31f48e67b19cbe8452a3b7005eaac77f965167a3c445cedff0feba7b20a6b6cfc578fbb0d4667f08e7813e00d02d1155d862b4971a3dc7db6f0c5c877ad6699ecf2c7510fdf03e686e6cc00099ed537ac51704d4a7e150e764e259e2ef7ab8ea5d0018e86af5d2211bc491008af9a0103164c0869df157c9bdce67a364852352abd6cd64d5c886b0de14400007c746848225ae6232ca89b21ed41d850210802f398a0bdd32fdda4b3c2c5300d17c4026bb86b03b1e1835e4faf78d70e63c9d18027c1cc225ff837aae088100d6e6ea9b4e7a8fe1523c7fc4a9ce7105726a59a885c5fedb3ceb5692d065fa0015371ea441c01a5278739812359f22e4dbd1ccf5349a6758acb9552d8f2a3b007c3ecb2d615bbe75e5a3f9bffe60da133a6527cd5d04411c0206aef84f0ca80001ddf58d99ef75406767bba5a4542835e8039320d01928d8d21516b90715ae0075affe226bb59e2a6e7f780a0947b4807c76722e9cffde6e35b0c026c039550040c75302b9bf5030e29a91b4fdd84c454599e7bb9ff8555198d5bae507247a009a05a3c370e3217fa7126d073e8947601c83fc78768e98c1b8b02cea6ac61200e275730ac955b3e5f134f42404d30ead3cab69988ea942c1a99a85c47e21090013a9ce37a914ba23782d0853faef6f529e2a6148c5b8a8ea47713822a3bd1900345afa32a9f063c4ba996e96ab78ffb59f8ee2b9872cde16e5b54a3259cd4d005d2d4fe8c96cd4d7cdab299f8ed318b8a3c0adfea5351291295a48dcbd7816003e9d337e128bdb8848c265d4a24d2f2af8e5ebef58487bb2b48eec4dba32b700044157a43365e14415ec41e575091af9059d45b225f5f1e65cdd6c6bd95dfe00d8e87e8d09c41854029f7483b47d167bdf8a45e67243e43ae251a2377b6b86003f42943ba6e0a6c1053908c7ec8ee6d18448a1ff74b353aec8e5a2e1f0788200a4de52e4d14438a4b5676899d2f0b16a4829b85f95c503d522052b13d2529500739481bde9bb0f199e6634c7bd81dc8923039d7ae43233a857c888adf5084100d0ab29d1c26a20494bd835d9ea8580f3aea510a0865520cc03bc223ef46e5a00b84b94d75e2833aed977c5eb2469e3b8d00520f52ed339a5b32fb318de301c00f94ae7cbbbc4243770e3b0d8dba49602801a4b4fd681d78d49b77bfb987f9500f584df73f3d3c997b4c8c06cdb82e8837625bebf5b112ce2024426158c085500dd36a336fe79c10a83c90661068a0634ea55995eba249eb73554f768794dc7004a82e0e49ee72c8c42093b3cae8cecefeeeb4dadfb486d13720ba62b0e6a90009c6449b0f56bc54e690d49ec6ac59440819a08fc6f85caa0d41c1d50d5dbab000e16a07c1ee3dbec97116d3ea398e1719ba688be8e3f5f6160e1bb1c60a5cb00524c4fe4d7daeebdae17203b99c167551e720a77ddefb6a7c7d32df0c17f9d0030baad203d03de456540aa8cb59b0d2762ce92306e5a78178fca1d81892c240040c0250ffa4f22768dc17d34981373b677b4d0ec3a96afe54f82491885a6d1006afb14ab979210213205a17109321ce6ef98d63b03670ed4bf426e887e6c3400dbe2243666537aff8513ad7f6079567152e84473bb4c87dd4e860c1c1be38d00723ca4dc7ef1e12f95cf639c910ef6422fe70354809fee37db7210b0c972d9001fb73dcf7bb0b5fd231273fef6507627dfb50a0a983f626d03824add7bfdcd00d8915f1655dfa8c272b2234942fe83dee42218f6dc10d548125400445ff0b400d1e9c187ef7d956f4a58bb94589a8a49bb1b5d276ac34b8359bebe356f340c009db0e3352f7f9d1448b07013f5c251d3342aec064894d5ed3a9fdacef6edb4009fa3a188fa0aa359b006ccd29951ee240755a5f981e31db9d12f55c1ae1fe100ce7a113625424abf132983ee5dd36fe6ad074131c7cec5ea29e0cc1755eb00002b1e6d2bbc8a25cab19c85da20365ce74716f43865d3196fce911a49f1e25100028b7de13fc550a3cca9c095bece3d950145cc276ff93e45e1e18606f0a76100bc48f658578a2c11550a3e9c925774f3545a561c700cb17041cc6159f2b9f700f15d1a4ca0ef6efc9d9193228362aec46bd82bdb6388e9738fcdbbff67dd31004fbaf0869cb073eac20791de1d4218901892db3af73dcbe2bfcf4b50ad0f4000f282024d9ac89f88649ed6f6aa2d877091d3440490d789f9fe8c086aba65c0008a717433ef16166c6aa52c67e82bca52cee3472113d7e850fa70812112dc2800d9ece246ac1e68dbad058a838892f4558cd72076ba246975146792510eae1500f489b28c2e77fb80e06c7ec1a9ae740b6ee890b99f583f2a65b5cd9a5c168000f63aafac1f4967a0a26bee4642e8c8f60cead70ccf1e5af086783dc7b597a500adae47f5f7c22dd8e797bb5fedb418b0d35c6533f32edbd959f644c62801cb0074c85bb3da42389577c69ee0f0ad8ee8849cf76d8bfe3d7f7317b48e59eef3004eec2db00ba7073bc06bde933baac44aaeab8c00e148623b9c68154bcac6f000a5285dc99351557ed582ccf450ce456659d06f8602a0cf0da7cc3a8b5910a6005a388451792957da4cef3e486ebaf5dc63b43b15e65ef3607a2ef680e3dc2300b63bd2b0302608da835a696e013a4996bf4917d3749a6909252b0cdaca7596003bee7e5e5121395be7463706f51a45d57d7d579a423ceb1e28360d46b1bf310081aafde00f9823b2159fbf3870ff1c6fdbfec25e18e93dd5e51a15c12c862800ab2ecccd017d3fcbaf01c322ed6c83ec17a713528ada5d03065b8906be100500a69e23b55f70caf87c61d01a7443453c6c0f30378ffc907603a8eb608fd24400f5d305685a19da9a3980741dff89714407143cdc4bc25e1992e05ba80ccfc900fde77cacfcf882eef0eaeea51d0bcf27bbf28fc4bdbe42da0fcfec827a85f500a09a0c7072475aabb18a44d71c9de3084c1b05be878073854f2114f544e0d500f150b3a2c91a96bcc1c10593137869bfedf6643fcbf87e711d7871a392d189005a0e93590cd5fe7cb489f45a469fe9dc77d6a8a3973bf08b5d2a04d95649f9008cad0188b88288577443581bdb75e04a2ac6277e73b80fc1c12b335694803e00142aae70d1e09f78a68d5f47582e8753db30895992c2101332689fb8aacd4a0069b6607ada25a7edad09e69192857cde8d0af956a86afe04a673f305f81c6000c0164569b69f7086ce15ec66a2c96f7c0b09f15a3ac8eca1b725fae33a9bd600da1dea35c3ddf01c201e8d09e03b5d52ec5c95c02ed92c69c6a3019f5630c7004b9d68034cf0172fccb396a1c805bf280a4b3b7954d979ffc12e3cbebd846c009ca254566c5fede916f89cc334b0b62c1c2d927c6d9c6eb8d223fc911bad37004c88bd04e32f82b226e848998147cb3e508a0cc308b95ac2e957de164ecc4000e607fe3e0b97df98b12003e80ca374454aaf6d42d55ca8ddb423ff406d011e006cc9ff1686d97b38f24a9149b96d8336710f4dc050d88441351f4bc5857a7a0077d08b37e7bdf2eb8edc585cf285c3adce77286a916fa23a1cf05a14398ee4005639c49a2fbf40468962e2972948fc469911c66c173820a409ae8f937868900023b08d845fb3de8aa9705a2481ccec0850c4e5d1200f732f52844e600c955d00b983d6b93199f9ad78c0755f5ba2a58ad0955747f3efb2dea819503214ac1a00599f5b0bedc005a49f9822053c0cbeaa092f7a613fe977a38ae439bb15d73000b3a6aba0b53997688181683d3fe86f1d4f86c730370d029fc1ff3d3ab475b200e7c5daa6e4d042d93de0983e2d701c21f8ca4cc9890d05881b2553b4617aa80087472003bd5b253a8b106f8e2ac411d0e6c52009b101d5dc96f17e08e6569b00e5865af3cfc331eeec404a908647c6960cb55d91e9e5ad43b3cc6f0868ecd700e141c4a76969513af32db84e25510b0307d784217fd3d04e42d3fde4eb0beb0056c830a4671d5c6b383bd9033b3931fabea2969a7992ee54acecae72a5562f00f9f0bf51c61f60af6de51e47dc89e27b7d5f263f3580321c02bebdfcd7860900152a83b625119564602d20e5c7eacf04dd540b7c40139f7d286c28c7449e9c00765d4ac80a9a08380b9fc2d2b9880907a5c5e2a9896224957894726d35b904001e48aa68fdc32a2ec6a39148b979b256187a8657c8cefc13dca1b5240cf5c700eb57380645440709cd76a6272a9174d6fbef3581332a2d9a8398de1ef60eeb0028b716819fbf7b02072f27de27c43aea55f05b595a3b696af5edcca776049600e2af2874acb95052a5c24d76fac984991f7db98dc5abe2bc5885d3917b54a2002af75adc009c4bed7433fc460684f58871bb599acd8bde5d0ee0894df8249e00c7041c671a6b139521e944b6820211881f84e0516d5de7d79f8a61a3c480c70089eb0a810415c21d644866f4b330e1c4f94952fc263148fc5556cf46d9e1a20030b309d6799da58090740513f921976878a08b1502a994418f6ab075be974800c7477458812e994f9ca2316ca76f74a4b18a56e7b3df8c2872bc6a85b4cd4900647b87a325a94700807720531b5b8ea0f30c2b9b10048d08d21e8db5c837b00082848e8ebf8a364fb50c924717ecc5269777b53c4e0f4515d90f1d9538ad64009e189f07cab37c9c0ca9f9a44394a706f9fde09d24e392e3f0ec822383276800f58868116f0da8aa9891af141a9bc01f82b748401dd5f9e4965bcfe94424ad003a80bf5df46d3b7eb0cced1e11f881ac22956a4f24641b3343518904d50c8000a8df65b2459c986cebcf23587cf8b119ebf8d6e5d5de041c79e2bc01b4645800da25de1a999f5973eef0c35b19efc0d8d97eb990c14a2127b69305f5c0074300776b8a8a0c186de55c6c39040a482df4b9b8a961696544f283ce79215fd48600d374c91d18d90879603e9c5b1718a80c63046078009243ea2501921cc91209006d1f10416276efaa0bb6378a03ea0461f18f9e6dfcf13e1c948b200cd99c690088fbd6b678edf4b16f954b10bbdfdb1584d655e3409bf49bf02688b52d67390062459da5d49ba16ecfd1279cc2e62ac3e17b3c8ae6f9ea56748a1a98cdbf550036e54b909b22bd5379a5c535cf0d9d044b9eff794747ae911b964e4022421c0028d9212e0f20ba8b537db7c378307cca31403bbd8b5e6f9e7bf5019396fa2c001e13755a65ea73e809ab71976d1cd4a7f71f98f80738d545346d4e8392570b006deae09f2131cefa9f0266b8990eff47da8e0326714d69c6b3954a3f3d0a04007547c456aa1623ca2d41fe5bc34378c58fbdc69c6175cf3f7f9666369d9d47009bd6725904e019c4a6571cf5d80d139a0c2ad6a5bae60ddefb6e7dcf20259600ebd405332db962563b4b9a127385b0e6fdf0c242f881ad9ec64835843fa86d00d2b6ab2eb2aad753bbbe89bcff7a0f501b19daeb682531b05fd1c918bb26f100fe896b1eeff9330394380ca39e65f455c4f8a938432c7d93e3bab7420a7ea70072e72afecec23df17e0dd3cf67e49bd7d79ca23a20b5896dc70c47a18380c8002078e50bd6a35bfa34b51209d46c5a4d9e3de761350443cd41e952ab0e2181008d7bee3721e2db3311c6fa19ede89704d94acad2fc91bce498978f00fb894900b2b4a800f55b6a328ef0135c3c58d3df562f589a019fc6de2a538ec966e156003d527bd51a1802bdafbe538cbd6a80a5d30ba04f7298b64c618a777315e8c10072e59370ba60f5752061e2856a94ea921b06d9fea029c1636f9522f9362eb400cbf46dfdc0a125afee14f0adbc597ba0622d17e7dc2d6ae87eb3d4b2533aae0079473bb726818a56951dd34e6ec8c95a5592f5faa6fe3b6c26c8f0feb8b4d900e59bc85d2675e21af860b103f1619008eee8fe7491bce6157e7b50bfc33dec00e8d3f27e0595863569919669fb3722b5aaa9f0ecc9ec71796c2013c22e49f30089ec440282ea0568f5f3493280db2c30fced0c3c8556d07ee58dc7cf097a050098da822578940102114739e56fe4919d95a1c9cd11a43c2b08e1f457adf825001dc43b5d9132aad7677efb444a9343737eeb87fc24f0d9b5c9324d1d81ad2800a2847c3387eaef5c78800fa518dc743a80bace9b776b3559e8b53fd56fcef700ae3535dd172b10c47449f8b55c5c93a97595f464bf977f1fdf1b0a72404e0e00ed2a755dbc057d21bbe6ec60a363f753904094cdf55ab77c1a525bcae6fd8600e963a149ecd95bc8a9b4078b076c1e57532163ce970b3ae630ea3030facba200e2bd2918df31f932adc33d8e0870152d978be331d231276373cf281fb78026005f26d6f77c78954d70f6da1f7e3a4da81acde19038558c13b5ff48a85e2f0d00a467bf59c4140b6eaf1567ff474bb7414ff673a620addf056d60dd41b6c60300aafd3f9f541561534d3ee456276b692e1b73d70a8b2f7b8737ea3adf22747f0065b7d357b4ac1eddfb337916dc67a6343bc8034dcdc68bad68a6f1202b63380000156d8fb737dfd83829474e67b507f5698dbda2d1555847aa9201cc2478d0008a8560f2b9d9d2989f945b86230d68dac29c3eb1fb7563fb6bd0c07895a4ea00c9e0640552a53bcbd2e56ee692e92ae7dd5849509280836a050709ffd1a370001fcfa9efdadf8ee8f3604173145654b2d6f10d8c1a04c551bb971715d6f9d80099db01c9776a16f9457328828156b2370636da01ab23cad52626583d20388d00f90a213675169e97acfae8da714c1c5dc0bbf1ccd2743a30ccb0ef7864f4990058c252ab67156c28d56c9c6d6b9a4f8f9064f6c77a4467c93b72ed144711d0005125599fd0d1e68f5cbaa49fd11ee3b2aaa9fc55635dc64b1e7864d2d3acba00fa94148ae608dfc0d0d134c3a5acdbf2912a58b71bcf9c36024fbbf2b283fb0094a2e3c3766b9dea7ec27adcecf20722173afe33d2a9fa4769f79f34edc0fc0035e68bba6b2ad1218fd7b187ad509a10f2f6070497e5a1f59d7476772b2dd400528f7f4e8a02908fa02c287e41708bd04aa6c241685ec9b2595ea95f74abca0095b827a448d5f22ec33b0be796487b789fdd7a859a1dfc90142fa0b47435d5006a2d22d475983c43e10a3debdff46a545407969894fb19aa11500b8cf5f9d600f856c634f66b6ef79bb51bbfcae3705a622be8c4710295d792086bf2816cb200425ef640ccba8c78be018f3fec6694ca5a67a9949a63400a5ebb7712aa382100de027314a77bdbcd50009056e91736be2b511ab0cc170ab59d7e8c71fe8cd2007290023011fc15946daa1dc9a1a062f1be77bcaecb26643aeede5f296b5c9d0040bb8874bf6eb685ce21abf61c4e14b1ee8850b37b41c496d570184be4c462000eed13a3f9cc166a54d6855998329ca9f171655541a3735145f622cff6b57300f8e66bb72faf1b2235579f9583f209e0cc8e0b64bd70e0b64bd539dcacf3ae002a993613bec5044e9d7a2d364a8cec10f4914932c522b7255307e42c62aa6900312f1043549bb85d1747fbd11661378c9a831c0901948eb5a46669aea4500c00ba409b738714dd9db2663c63efa1ce73e4258c8822cd69f4b4d6b701123fdb00f12061b48574a69f3251ab864fc0dbb88a82de8c3f2a3581b8cda709d1e4af0064170d7fa30f43833db08500f713944d8dcd5f1962eb5f9f1a7168d397540c00397a68346377998952298792d4da3d0a2006f7d5520feb49ba43418c59cbb5008ecee5be27b70c531d36e78fedd7048f944b639efad67f8b0a70989450014d00140e1dbf6ff7e39786555c4f8dced432c0aed2f501f5095cd6e1b54daf1632008a08a64c5007c647ee6e15c5df58986cafdad3d4cf52a26e4510c40fd3dc3a00fb20882abc6f09bb164fdec30c1ad0381c3627da238a2190d2043f9eee328b00c2db084ba595aacc682290ea13d9f7670360ca1be3a132eafde92b1281489800310ba9979dab701ccf735353e3100b5779b6b512391bd9eee0ed49be60f12100fb2725a47852e47ed26485a733fffb9d03a0e740a23c36f22c57a687b8cc470067b4a80b1c9c44099863f7292ae4188f7f824bed026d51335254a1fd9b932c009fb3347c8d321e7b19de4a279430c43a1a50b15f2786139df6c8b8f31c42e5006a7e0e76abf75c2bf9dab0298f28d9f6a3824e3e115d56ed0b9d661870f55c00b74d287948c5c47fab01a87aeb684e267f273885af15043ac9c82ca69255b6008655d2f097252c96b83b8725874a1f8910fd411b368dfc5d2ab8f934cc542b0009aaee8691a7439a9758677eb9869fcb8678bc03a9610e3a761bba31e85d3200f56557c9fd94d32b64fa508271537500988922194e3632cf118b1e2b43c99b00674f4294299f526a1e9d1f410ccd0ef63616a886816a6e2cc02c6eb173050c00cd36d5d278b0e710c39183a22dfeed25ee3f2e742c68e610ef67fe4316496f00ae05bd8e559ae825105649580c0882582399a97305a88b60291d15d187e24400ea2b4539faa72e6a9670871115fa04aa704ddeebf7cdaddc445a5d8e9e172c00423088e6393c996553342b558b79b57e729341dcc306373806b700cfebac6c008d704977e4f436b7916eb8dcb04499b4af4f1b2febeb4af45c688454c0477f00b400479eb9e06f79140ff61da860f3d4a749831acb7ed751571fccae6e51990038621e6b2d94799b0508ac433ecd0ffac6d5166ac6348b87f97a2193dff9fe00f9208bb0e2cae15593e3670bd52b0d9f90ce8674516894f33045b9d06ca1a60030f4439399b0cb992303ed31afd90b882cb4638f6acf4baa7ec491406d0747009f3f7ba24bdd4948ab3e600e114451c4d5e370b3147811a58f34a74a4cc46700a5771f7c71848478f8e75ca34517268d2c229ef39263ced5001ef4f8ce455f00a5b9a9559667b0de52621b161aaac0135f6e8e2502fe9ca25c3336b04bdeb100427572de796edfbb183b0d0007134080644f5507ee56f6ea6adcfea753c08d0030f82b5ddaae6fee630bb652810fa3ab12dc5f4ba2176c44f69ff2abb65e5a006d7ed3a8d6a15c2077a811a1e0ef6f63e87d2b60eed58171c4bd89067a004f00b5848a1cfc07b79387082647f5101d11a4f20fbac814e4d0fc1a0f69649f6b008962a729e302d48a64f4c37dfa463d7724d82d13fd3638d2cf95c50b9fc87e0001877918c5e41be2a1b1628bf6929550d49bb62e079faf3a4a7243a5ae592400a1ff4bbdf130c5fa91d183d2f23106aab4ff5e2555caf755f99caf84fed70f006ab58db2be3f77ff5b71c5787ad0f0fc0eae1bc4a89f3ae62ccd6332b6ab0700b553e96d5a1b72d523d36636398b1ee87fa7919d3b0896db64614aebf195180004f9770b61a4faf2a86df8d8009b507b1b2ab9a6d8f8648d4b67073d1f065600b74e91513d61711df68d82ec4fb5b86ff25e31b77957b14139cb9eab31fd7d0098639941daab3a8e3809440849158e4e78b5a91c833bab0256f4426cb11a5500a266a17eacb0b7dc050dd06e45591ca8195e8bbd35a83e21b90c943bd0997b00fae84d6fb3df93c4043be7e7294c3fc6aa6975dc08ff9aa005f0cfb60b97a200d4887ab8079d3db4ff647d688f3930ae858e65b11e54eb0d8c5d0f4947122100c8efb22950fb671a8999ca4f1c53a8a7d5adb5b5bf961a0182cc871eeb7de200f72f773fd7f186f99055c18192a162c7749bb60aeae595147e0e562949e3b20046ac74aee4fdf0a3463e84c99aeabeb2ce4d8f3ba1ec1aa6f03c6d2242640100dbc73016695e980825ae1616f2f2de83a683f2d04d3a22ba14bb2fe0780683006ee4a6ea7c2f4b79a4b4434a0e9e8760ba75a5a02f2b36b67c57596a9abb190061b2bb4c440d049078c5fa28c182abee42b7d4ea04cf4fe50a4f4e7e6087d50067b0c08a4fb59618a95fae1ceb496db4edd651dba3b15dd2bc8c8ed962ab1500d5f721ca19010cdecf1ba0dc53ebd4ba2685494d0d6a1917031c8177591b6400ba7774bb465b133e7312e711e6b932650c3504d106896de1c64a2b59781f9d006d8115f0c96b7c8e68df053d620ad71bfc8cd7e6fddeae0250f6ced9c0294800a1a8ea55cf991cda5afdd4c109169c7b9d9d90397303b036c8538b86cf3f7900ba70f67c5fdfd5ac436a7c2dc14909c366f940c208652ff2c583b2b0ad79aa007195404f1e4f77213a96e5e46ea75541527233bc6f7fc998eeca5fe5d0b165006163eb776cb205635538cbc09593b921233e50cbc8bec81b117078540eca34004f3510df20536c19fb59d54f3970997fa7e303af0130234ce3604ac9e8fda5002e3dec038083731f3a88dbf8a146106719d166d6b836ae3a03050b1c6be6b500871d53e6560175c72c76018b31bdff1198539b3c79908a283a519298718f880042e0c04e2969704b33249d50f1d3c6f4fc26c93de32115847398b836d62e4f001f3ce620c1ed4c1ceb33c5a15818286b2ba73aa79841051e0bdd6b96bc0c550017bd20e36287209fed5516e4fba09cf65ea8c089184deb61ea4727304d8bba00c5e91839f84a526cd1775e1c266a5cb566a0c2b045b772f63c8a3e701870c0008558f92c0ea2c727845bebeaa3860d523f720f90faeaa7e38036e168c1186300e310eb5d2733e1119f8f6dfce9b3bde0e1b8df3c12547f1f91654eee3b858e003f537536d9f7d9f24f64f03bc9e540ca9f5cbb9baff75556ae92c59deaff9700c8dc91f0684301cf94f0f83c4b8295b37c13eb2cc64c16c0fcfd3b7c6cf8a10040744aa01e368053eb865b03ec44fc58b82bb87785223e12706ae991e9763600da1cc0e4fc72f3c6f5b0fdff49ab03dca042ac569624c204c0d9f413a0803e00c9a124cccf8a962fe32944c6cc20575179d5e6b831b2721d15bd4d2c1702d5001dd8e678c1f2ee237e21f3e865228def7b734ec4948ef3e64b8ba253b542ad0095a56af45da7a34664a80313ea23a00c41637fe13bdefdd5c585376088ab39003f063e3968ec031434600b5555f01485fa3f6cc19b5f941d3c636501b2cd3f0049ee9f81ebdd305cbdbd013046b20cf78e390a3a763fabaa2fd600a8316277005023a623b21a34c20c9f7f56ec750d081da000d84c1d3e34d4c328c460d1e7007ed619e12b273cc74399b42077572a24050fc709f26320c2a4c334ea12e13d00246a785419ba494d8673cee29c8555f1ddf9f3322317eecaab0f6a755c4a9900e24164eea6c4f04db10f10a1fa916ecb17adce028a9c53fdfe1ae6100b0b74008ca0f4dae75e0caf81c654340842087881f411848e0274be5c968e807a5b1d00684321360f513207e546afa6c715745a867271d9df8b2f373afeb6b4240227008bbdaec25f04a2c78b30a6ecfee82659a9b513d2b0feaa5cd08c02d30af7c300c08542500bda3f7e5dbc0455ed38f7c193fbc731457712e49457b7268ba7e30083f2a75eb17e98b2812b685f729729fa372b4b8dfbf368856d341863fb58c700c6238c75bfe0eba724197231056442d86aedfed57f21068d1ed09258441b5b009428005f75da8ebd26a507cd989970f4ec9ee674691f9113e089b875a0620e00c1d6b6af36e8765d577f749ed71528be2689f0d69c02f58dd2727c06da87550018ff799ae83f6037a15d81bf8131351c6fe2a041b1108e605a0db7bf1f1b1c007f086455d9f56e93c7fffbb2a46bc24eef8315755dea887a79172a702c6ba300cbcd72734f3ae18ca4257a4adf81d8ae95ebf707c415ffd75f76582af5f46400ff411d2091a64d4cf89a57f78ede1e4942abf27b65ccfcf59707aaf59f574d003ff205d324e75ac55a6d39ed1f6033eee04a745697532f0903759901619401005d7467d3a65c1d16eacf2701af324b2b9223befd73d6f8c259cf4e3fb75554000cb3a7a87d21349aa2793efeb18d717adee6c9f6c3910fce5b86ac932d3c1d00adf57e3c29204679d386045082e025b58585caf472105b3cafed3241abfab300614e5b7da77da0a40cbadd26f084ab3773b6eb383fdc05766f3606e4ed6f6a006be5b61e33c11be825eec691867df18f93de0e8eda937a930bd7b0c0d9bf18001ffbfdce490a59643b0c1c1e1592249242d22c285b524d1eed7c9fcff86610001fb35a149aac6945e9b7b1c43025b0e0591f27e0684f095b1644650a05b8490078c958b71a306ad3de9558de067cc939543be90546f80815accbf4da834074006c8a8a43769b0fe32b62a00273c65a43f7b5ee62f85e53526688dfcc20398c003beb7a601fe0f42d29a96f840186f8af0fae64948b45d793ee93c56366669d00059979eee01977be0fbc9f91b97df602d73d19be5fc2fdcc59febb5ecbcb150038245f850a4bef8d4b490abb6946ed7af15652b867ea531d905bb0a8952f8a0098fd71590e21c638b18cd09e0a9b232a037761cfd64c36db76f49ef6398e6f000fba00ecdea10007576645aa4fba87f3b77b09b5a4dbd4800c8f3fef5e90bd00f5e68489fead70fbae59a5a430cbd7c3b0abbdb86c77a9b4c494166d4932bc00a79aead746940dcf9f321821532c9233c1f169b9940980c6fc908aca306cc100a3c0549c1ed2f42b271f2fb894ea3fb57562a487b5413b8febe1efde4a775600b2186bbc3054786d58fb64696cfada9054d114bc94c1d0b439d262c4a5fc2f002b652a3310aca0d41062528687fe4c88c6e798a2e47a7be1d3d3738a31cce300d145f7042fab7b6673baf08f70fa22202d6cbcbe4607b7ce224442f6066a590048c8002e91896184c8054cd982178540c4a360c274a89392c5b7939d9933d600d0b03701a132c4424eb2227baf8d7ce0a0ca13cddbf9c27e4960a1f17babd700cc14280c9ebf8c4e649cb6e8f2b652942e8468ea25961f000044f7bf988cfd00b458eabdc8b6d15438647332d396de5c62ea8accaee1fca46e419a03f09f1c004f2be8b274f2a0be2a6467105d2a935498fdfd698becea63cc7b94fea42b8e00c852439f12e24fd9f0aa3168f04169e3a95d19ffc1904593eb59625ada68e800befe0fd28a753781afa6abaccc4ad36c13f05395acbcb6234e9ea4fec2bf7b00474b3b90de98926e42cb5de9e8e2d0ebfd4846625895cdc7dcd42cb3c85ffb00e00d834b018c0f8e67fd28f470584682df1b381e31e5ac4f146366905b8a9c00346064410e6cd3f9521763ab7f2710adb9caf53631225e6fc62a6b89a5684100e54d97db2cdf2182d5198d3dfa418d1f59ab5dbb35e531be8e1f8e42d3a13e00a155dbfc366d965e4be279246f3d5e10b3f8279b3e47ceb221a6d0d2957f5100e2561fe9f4fcb145e914271cb062c19021d07240b33d7865959460a1ab9aec009fb518e5069797a1b1a093fbfeea8aece20ccf7eb002c6fc597aba208f94f20058d782cc8b33d9ee5cb98f22c4fb30fad29277f7beec994941ced4c5f2db020073aba53046858f0d4859ca4830f8c7a0edf9518200ccf545e1ecd196352939007d47ddfa33002640435050c9138833b2d20907bd1fffc5884d25b33b0375b100922389b8ebdd8beae0bbb07312eac66d85f1685008ed63c2620da2e6dfe938002c66f06a29ad1abffef4669fbcfcbe32bd14849ee7145d4ddd053d36dc2fea0013427498e011d38f0e0a9667823933c2999eaffa3be71ff035da291da2e5170018f7865c462e2f8ff21a3352a54000c32dfbd234ce9218415c9543581fa1540038b04898fe3470f55d27df9bd83cf2d80868eb9935bc18b96f1215b46d7e3700146c771fead627598d2032be3ec98f34e3b4f5ef45305a041a6ef17afdadd3004d8988532fcfa228fcec966fe95b22ed948ec216b65160095e9808786a5fd6000e8ff349e1c42136d4506d9173d843258bdea44b577e1964510193203873710010adff53ac900d8c37a2828f9c3c6966e03ee16999f65ca7ee5c3d42871cf2005e3a1abfa315da5dc0e90773742daf41b5d5f217fd994d8545a6ab926554c50015e55e366b74c77cc0db7260def4b484ebc854841b65bfa4dc2e39e42988cf0080ee5d2aa21c6673ec03d97a61ccae49aea2c213bab7dcc6ad791e864901d600b676606c74a4b9db9a43e4d9e233b08134622459523ee1f1a3a535fa2db7a2008a356c77ff003bc60b9235341554d026936900e70a1f06c1bc16e578e6cd0d000114162f8b863a3c0a36af23f22d96bb58b494cc4d9f595a54f834d8984ff80036de40ad13e557b896e3ea4d4e00299fa09f8ffae365a51f08ac6ab7654474007f6400dc597c08e39e3a438e06ab4d3edf0ede4db79eb94187b2aa4b56f6840055332e860d32b488459757d4adcfb54325fbc77322b3bd78bd49ac5b2f07e300651a384266038f6619dc675720b089a7e850b67b7e6166e0740d47f98df32f00a3233a9eaf45f9a73557a61d98e70a6006bdfaa8de964a9d64d3aeb4e15872002f820b7068fc4322dab909a767932a037577da8bdbf399ebcfc14e947f3ad60062f47cabe9819f882ebd98f59a1d2a6ad588a77fe29b86627767f67fae1f2b00705949a833eb269d3749467ab16b62ca2d857b7b0df7037175a0c8914293da0056da8daabab34af43021f3a4f617522662192884d801657ce54c2ab4e7575c001d9d6479a5fb4f9c5eb5666b2ff4e70d8fe58a89c9b4dcb4643c0808c492b60010769209f61a4a485e7b578b29fdb00b2397c59ae66d2e785ade101d93843300af62d0dcf6b9e67eb82fee9422a801d74239a4a5a5f21a2c9faf17cf72d1fb00400df70c0e2c862fdc423b04a69067e29a37009ec435f54e98e57585d33b5800fe0dfad492bf320de3c04cb18393acc88246dd8020491b4d0803877ecfc6280075eb8902213c6a3134e49a795cd25ea2d2e347f1e85865aaffce2450eeb18e0078e850cd082f095354f3636a768b01a2bc0b3986a5da9b388db2d02fd90a5300838630f9d189e891e8b51f5586fb44ddfb2c5602d02461e784652e226f10e200b1c38f277cc62fa628e897b1480690a1f55fd88490adbec85e46e57b66977a0083093c0d22e611df004801ce59eb55fad8e3c3c9c44ea33a07346f77ca68cb009987e1fe9f6751dce2877cee17deea48a9109128996e4e2c51c015160bce5e009093ceee84772d60e1ef171a8e50d247f03c003140e267294d8a63f772219900a7bd565a8f1eab24a2145910c2e5836a7af7ac2728b14fa74f9f47dc7f2f60003a8e8b00d49990c92f60760c20ac3db98e424a2045474c2c623fbc7342b9a2009e33a662866411944e989d03f1046ead53ad4d2abcd51f6c2b9713ed9460b2004830dae5347f921a0c6cc44e5a0f575777fae66beeadb714582fad7b6e54600064536da4eee006100ff1a8172ae4ff9f4476159b29dc28e2986fe8c7596fd0003eb99ed678b4befdf1444385e855dd09ff436ac36e94b62f965df4537195a600d7402862e182c0d2c26663583c1a6789825a9e9114e7a4e63b1dd46a2f8db20092a472aae0793067ea3b94440d5a45b6b6270f50f41cfa5ed6e4487d13656000204410f477d8e48e229749c66969719b35adbfe2db2c93ef4d01eb22b113f300ec32b79b03c0870c6b13aaaefb825fb4d691b21e10ad013e3fedd31a9f37c500c3aa4c07e18d2b4a0b90a76b606197d5bca564965eb0afae24b0b363e9693f00f425e9011fae4b2f00f013f5866585062eebb29a0c6cb6d80bcbfcad840b250018c7936a2556c3192ee296e8beb4c665a835cb9faea8512e3edb4826ba6632005c6ca3f7d24fb576f80e75da7ae8f9ceacbdbe99c5fe1e2dc36379ee58bb8100d98147a1a3300cce0383a9231124fb117d7c8216e08938889b74acecce8ace0090ba9308264cabc8f6d3348258baa8e4186e3fd65fbf1657a8bf44b861ceb800416aa8c07150a8d8f735b5c8122bf6d27ccb3e8b96f33dd525f39b3254f2410099cc006fe3c51b2b85543789b73a8e806b544a58c25996708fce96c7526af800b4c257e8ce2f93967d10512b09e5e320056a8ab8a981dc1fde4685090a7312004dd30c94c20a46a7077ef4f148b4a103a09b9ddc17448cbe09d11eed175a11005d888533e6fef7f48b4a36de65a7cbc5f8f8de7f6a51d0830e46f02ac6d3910050055f29629a677b72516fe016b12a87f556cc35096e0aca9b42a1117d3384003edd08a0fa18e2aaf382d6204b86203060029ecef3806ab636fac718eb6b5800d8eef5dcec896d6fdba7ea8dc69ac2cbdddd35d957d3e57b1d560577bb0e9f00ca6851ff7a5f1a28b13e01e20f7d675370e73ddeb018d3da873d106c888d0800b661005f283223c9c4f5a0b57634294a1420852a64593531ca280988fb4c5a002820cf31b810c449d83e60aa0b090f14b143d63096aa28bae472c48ba3539b00b21a33385791127e22fcffe3af4ad7553ec0889b8cd3994087a7e07ff82e1b00778559b25bf37b762f0a3a8fa3f391b8303f18996d779d0c71a65105648ba200496e503a3f97f740b680dd4f1aedda721637e0c77a7c5ededb090ea57bb4c000d7c4c95a666f7e9958279c743c6613cc48ea887503807eebb5348ce34a81830030edf57c2de75cd6ba9f55911e8afbbaba0ba5dde979bcd37405b4cc23c3cb008dae233d0143d08515fe73b45d0eb9f73738041e02a9abcfd02e0750f988f800d3eeb93e6a55bd51a331a50fa383ae0c364fa5ea8edb1e3e9e5dbb1f688bfb00740345f892cde042645ce4f0b74ae0c758d21201a65bfc9b44ad69279e345f00cc5496876eb9a36298a7fa29ed013dbe2de6fd90721519b76d2cc026d5e9100092e05e4b3015b3afd43fd6fc6405971ceeb410e045e099dbd2e1125594b69d00e0b72f3c3cdaadf754a3629eb1688acbf75149bfb5f3a2c07c9b15ed4b00ac00a729e9926c32dbcc9d7a195b3b85ea29bcaaf5323a90c0ea079b9c75eac63b0088d2feefb799f6074cc1d94a44f19c9c6211c92a30861ffb585c2b424bb552009a9debe758430b03112c8a89a52b4beba7574907749d6438cc150cddf40819002acad4fc3897d2a741ab646a273b7fb20630f1880da73ee433206985c0529e00d95bfb98b0a962f8caa922a7bad9ff5eed55b772c4cc8b8bd4a5b02d37bd01002e4fb5ce82ef5f8814eacdaddd64cf93c3461dfd56ebb4cdb933b15697a3d800f0bb21471ab3fe94523e659a268f5ef3fdc514f75b44346471e1755f299b5a00d50efc74fa02e22b17ba23113dea1d216f30c3b435a7fe57de123966b538ac00fec268eb51fc540269a0c728da8498df8881837ed0388668cbdcf76464e4f400c78ab1e9afce2c73e4ade1f56b8aa4766f56cc06f969f77c74567382a6a60b00abd1f9c350bb9eec70c54a5c17e82ba74edbab7e69e45229d6781ddc5dcd080006a67ca403bbc4bd4af85f39e6566929f47448be9619c4f6c93d90d090a6b000af09053ad9fc613165df007a23d14e60fcbf1d49b3229c7b7aee5e19a9982d00830e10b7deb7a0ff1f6212379ecb64da916dcf8092afec4b1aa5489e5e0ed9005c3988e38b343a079688ade4f01a6e3709ebb5d54be35c77cb228361caadcc00f832239a11d6bd26c1f288c982607385d662680d3791a342a07bcbc79519b90010d76c450cbb8637a867e08616f3735941ea54db91fed2efc12ad2fef2eac200cef14ae515b273dc03cb54e946c6c0b4daebc1a7648f433bcafdaceaca674e0018dbbcf4eff8584976bd66d17095633a999c3227264a48f8311dd135b44125000b1766938e33090fdf74b6b7a2d1538ebba7b59c9a94d7600e94a81c3f0ade0003d7592d40459049a10bf3add523f497bbf45be4315ee6781f411addb7d7ce008dd327d75cb9c807b7cb2db5f65805211d6ae7cd6ce804d2e193f21b203fde005ff9b0c04d99331ad4011767dcb24d8fa4ccf5d6f9490a80eea960d304ce5b00b3ceeaa7e9e3dcb10f43b1466d5ba0d51497e58db80ce686440325e86aac78009dfa9439ff25a3b5db6df0a2512a1fb2361197047eac10ab109a7671deafa900b234a1a785ca6c594d9b4d72dba2ffa8209ac68cdfbfb817878a53353a84fd00023dd0f45dbcb1eeb00ed4b6d6d6b17dec6293a95b828dec7adc36bf2bc58f00531f5aa8637d4dd48891c26be6328564b168812c359e7e32d57f58cb1127670041002f83748e84d02f7e727db8d52e84e8169763df58ffd5cffab2b63ad32600d568c6e9a768576b11dc3c67b499d873c85eb3556d37672b71b4b73f644fe40093bd4c478fca662f8da97f24a665c61fe0a6df03d87f3112e5df41c92a12a70014bba62c7f149cf85a155d9d3622d9df6390955917f853e45587866550168a00c73c9a02c304ee202f43a9506b6022d962032da15d10c580422d90acee01c300014b01d2a9c1be000b514ec3714bfeb8538c780bae79078b492373a5a7df3a0069acde0902cb62d3df200124e02690005dc9a7c265131b745517885eae2bce00210d293a98d2ef78e28dae286de1c122bc5975b48f25121bfb2e4ddfe0af7500a23de22c8224fbfafd848c296b334d8ee1716aebfdf49010d26484ace0c8c300a98f398c52c5534e12fd848fd4766e092c05cd622f7e2c117a1d9a1dd26b23004505a74a9e10b4c5ed3ea446a72d38d0c056256a06c3b7b1bdaa6b6251114a00a522cb77223b1164248aa9aeb3025635110e235f295e6a07892a0670b0ac29005b3264b6b4b3c40134efc3029e0111ee5fd18bf57845a5fc56509fe1fc4af10091490bb411df0ac0a2a29f668837922186ae25333e19cd727f6e26ac2df55400fdb98c5c88ccb4087b80d5dcc549287a586c5377cdfbafb0af664704432ea300d547093a4ffd6734a975927ccc2112de10f726aac520648d329c518db962cc00e6c421aa98e9bda17426c3e0cf393e94453c24f116896e796ee12d1831e89e00afc13f389bbe973cd6afd89c0a273ce9cb1cd42451058238a0be901d8e5c6e00aa3078d2acd8f415805ec3e255f267b4497efa2c44666ce356c5ca92e0fd8b00a303d22695dfad4b317035e422ffc13417dadfaf705d223f6b5ab9db1e9a570012a33cd6034922919a610e74fe77987a54916b7636a88e9ae1c526fb311406007e39e8e80c4852d6ace887d8d50ab2c05294810099d9e226043b76a87d70030058eb5f0dc71cbe97a595cd421e8ab5b692d650cc326c3baffddae103cc079f004cd317b9f72194a32897e9432c9ec033bdc65941e80cc6e09e00a38385f98c003a7d50848123c3949ee2d5f40a46782e7ad7a75d13a1d4a5e27fe662a8d3ff0062e5081910a2d4cf072af0dfdf52fa0579a6bbc26fd28a0de8e47e1d9d4d2100331d863cf432ab4d6d36c0f600b3678da4e268b2de8fd1e32b3032fd6ad3ff007f67d3737aabca35cd7d2788875ef6629e93beb8a1b81c09cf9f577995bdc3002b87be403289547198ceb7fb8632333bc7fbb3d99b53ed12d60e61da0ace0d00b1e07baed8011647afcbe4e59dba43305f354c433f8532d23a9d09053a018700382a06949bf02c34cd8451b8e45d32cbd224f14247fc7c89f4478fe7ae9a17004dc04efb0240e59dbb2f0db7ec0d4f19b8007c0ca2b9bdb52a5eec80e6221900643c6d97fa1832517c010da8257ca8423edeb3ff5f56dd2106f0eff8abe889001911a726c036ca14ad16f100d0e72975fa90f9ac01aeb255da537d14fed9260007b7aaac1b198db09a6578fab814e4247f97b8cf7cb7421c8790de8f6a98df0086cb3f3e47892bfa67e5fb03b9f42ca0d211a264fb924a5ea7d88d5ac4da58006472661aefb1ba4b7ef6bb5e3924ae3463ce5aad4c16a7f9221ddf13ff476400cd3ff85f8c6cca0cc8ed415c38c6f439f59dc084bdb52eae8a6d32666e7c9700d9fd374d1e3fbf5e9648f92b4001bd8287e52c73e3d3d820a4e3838b33b6bb000263db7a24e69ddb215e658bd54f402c772764a5cf7215267a3074f5abc1ff0008aa8f87b5f70dd6744d8bbe62b9afb1aedd8251f5caba8e2b4e20bd1086c300c13c12c89e5ee6fc0e52dd54b7b91f87a57281804714259bdcecd1eb00d188006a252644618f851629c29a9d8fea99244bf45e0a8e39aebe0e39cd448e61e0000346e41f050d926e8391a13e5793b607ab9202945658c98592a2b34d3c85bb004c22df6c6d0c2aba08c92c402a60ee71188d9d0e15c7fccab97865c79da89b00299cab6c21a42cafa11132dd0dc1da658957d849282aa5535c829cc920ed0a001aa3b13de582fb7c0244c7b538a878b739929111ebfbfaec3ea6ffb8ab4d82003b5eb0f21f003b59fe87699e336ba3aa3a961156038e151c99633384ddc26d0070c11cebc7502ec6b5940ed18cf8114ae19f32b23baa953d6df7bc834ddab400a8620da25ff58afe72a5c2e4813bf157a6c468a474d82c3974b4a9d2791b9f006f5d670d9a92fcc8e9a6ac71abb5c317b8dd6ee976979fc8f81cb29bbcdc2d00bc17ee61c1ee7bec2ea44613c32d3f84beed43f0802f7315549024c1bef55b0003f504af94e78c9f6b77875c27882141077c29ad6664ef5fdaf38566687253005128c521961e3174c8c5c7769b4f3967e1c3001f90aba6f885ed7793c194bc00a948063262f89ad0f2661c84944319f975b22c90e0198dda4a5cd5c286cbe100dda59d1144a82f0aaaace6b95c41a99c5bafcb4bedf2b299b5dc65eaca422b008d348c9565a22ff02f407be70f633eed10817bfb7c9dd833ac8a13e7534f1600b01c42bd07a2e516107765e2b81492d0a624b5e878038fee611e0996a7f11b00bb13aac5741acbbf832c56c554a01a3abc91f1d0b026f8b7f083073625ee9d0026cec140c69ba9ba473ad8fa172c5961b4ade1ba1871533f66d1396d9e8f340011000b92417cf865e6d22b4668e2578572c02968cbac0364fcee4a9a8eb3e400ee813d2e165632a1883da00bb9d2846128555d9e80a3b15b92a58b26ab1d4900f51e8ce25e6e7e284fb184b2166d66c18242207bb7ec54dfeb383137b0ecb1006023bce024269e1663d78ad1f09c5bc2ab781392efff1b3f6cb8d9a114faf400734def1a7e33713864437274ff8de4e01b20f721d4adb9ef706c94d99ece7800a71b80ab0acc1e20928f88a267d17ee1a543ca6d231e430bec3d210d74a3f50075e26cc61ddff1ff5eeccd1f55c395ddd44e9a7b7f723f50a3fee307e0b2d80039c4cd1de61d3b0c389e84e6aa4aaa84df5893d2a8c3ef1588d348bc8e496f0090fbe415740dd433604fd1aa987b844f5aea42176e53fffe73550881515c0100211ae1a118bd36e23914649ed7fd328885f604f805dd40619d75c732a40adb00d21de700b461be7b39782dd191655036ac4689f4048a03a8720c4117c4abee00f54eef34f878ffe40ff2e6bb048a8b1346c927924e97f646ae171a37aa587e00b6020d1d885106608acfb58542a236027fc7f91a083492e4e5cb89c790a19800dd4a6d8ff1688ac8d902391ea2953adead661c992520bed5b183876733b48900aa2c6e0dbfb8584700336f3de683eab8c4640fa9d386bc89d96b001aad97c4003391190fe5e4439ffb67fd2a01e69c344921b39b9c0bb395a0d947773c3e240019e36bd7dfa94bcf0cca573e46a6c390ae0c8605254ce0cbdf1e166e4efcf00090f5fb154f4034e049ab6953f1193823b187325578176140ddff668b4c302a00e352e531bb312f5887b3b107c6f349da5257fb13e9756383eeae03c78521df00d29e098af9af5dc39712fae5083da74766c8a1c5033d6aac73c0a2b7c27d24005cb637e31db19061450f177c6be56cbff279d30922623f4ecbde7a4c5fbfc5004c90d0e404a11ca8d44b3dade714dc4b3403166f4edcb6f9ee62ffceca7365007e1651ab2a2d2e186226443c9356412c619a193c27f37ea15474631bc5682d00db049a18bbd520771ceb98198d042d9aa21e11ea40ffb20ad451f6b79a233f00bf3e3139e99d6904e140e4bb1ac2261941ec429708c19c74f0cd8f695b289e00b6f891d18863af842619386af8b4e7367789cbbfb2386a1a1b116edde009390042d1cba425925195f525f27521bebd33502629d6569e6ef25bbf600c5ca80800ed926e07ea38b328eb3bcad1a16bae7dca4e920278fe4a1d4c27acb95bdfd600d48aca6a325e9498f3961ab3cf153520af8df3d7125b384268cfc67ecc3d4100fdd3bd6bcae20af4e4b76bff0ee94a6bbdaaacea163422647e8424b0ac5ee9007b8138bc319b70dedb5c0109dd1eed5e0ebecacada38035adb835b5738981400816a75aafc26f8348a961df2a47e980de4319b6656032a54e05fedf4c873cb0025499383c1b301de62a7a2902c581423ee55d499021dfe0b0b6352746ba849004defe17f3d646d6820635f77a7412c6067a5d8f9dbe3b0c150abde19b8afe30019eb68b223f0c61a09b455a31340dcf8708e1ac252c60137e596e82a9faa1900225a1f1ebd777739bd1ff3012a2464ff0e0da53ac3713b7c856800380782a100c9f77e902b3fdfc77a157350b38170e61575b62eb932424fc709826b1fd0a000ea086e79a73e9c734e76ba10b171b26dc62e7fa814fa0223855ed520e155e50074fa1739c328d13be8e8f3c4c030b0d4b72aa014dcd9704c4ff1afd5b842fc00d750056e2ba757c2512c14a33a45ae7997c52fada88355ae4b67285e66205c0007d064764835cbffb5f13d2742bce3ee3cc4f22b9df759efec563c43de543600019e6365ae9e46a8860624831777fb8867eed94101a4296d90a30868fbb4cc00b1394c2a8a3fa84c32ac89013cbe13564f24923a2e4fde4fe26fa2366dcb9100e6cff03c26afd4351079e7e750a8fdc55dbd2b7fd286975db67232eaf8e4150025ea543796b92b7c4ec6f68ca34ca60d926eaaff51fed8e033d59e9adb703b000070ffffcc64b102e3e1f198be3be5070c246498aaa474908a8c013b55f830001064ab5aa865e899847c680bcc1096e06167430dda94e521909d80988b5ca300d331add584ca7f81b70ac555f9956bedec01508b36e04e5f59a27e8a74238b00be59e449dc455d881e26143a1368138d879be7bfcc90cadcadc85d4ec24c2e003ef7014202be335228673437df6bb6bb85fa4ebf7fd4a2f2f5e52ea3d509aa006a0117554316927c7901ac7258b42b947c2054d09dd05f21cf80d5e75036e100fc5a9293a2329b974aeed1765473cec80f7189b1d2b9ab0471e7f5bd0dc2f40086c7e8114946bfcd18c456a8e47ff510cdacc63c63f0267e4d6b7ce37122250046c7c27ebf051915f3f2e653b6b02fbd79abfed9d642dfb71c2e6c1dfe009700b37f9310eb605c7b6839dd1741d1fa09fd244e898a6305c5a77882924a35a700ab2319d811898e14daf6423c92614c79f6dc27a08ff4cae2f308d969a5b1260059dbf00987a2b60c802396ae4a7791c57d2f9e9b8c6431477a0bc8da56c6a0008ff292733f8b9cca01be08fd2a6bb8e144c9d60fa0a4464361570fd49a8b8200bbe7c3d5fbb3de66eff7508e0af2623809a7a06ff2aaec3ad6db2d97ed35d40027f262ebafdeed2dc82f896643fb31dfd60c4fcd093c4d9fe580d1af8fd8660082c089711d5b0e10e612f1ef841104fc450749d26f09a5658e02f64a6a137d00dcaa4305f3d5e953d39c32fda53061b49637d014c0e8dd86c280468660bca600a9c74bc3cd04fcc6222cfb878a5f6e4dc5b7c75d337a7612970d14ecc7fdb5005bcd317ef82bb1407c0f60a1a5151e40f239c9969453db3b5e9e30d884577a00ed49acda47d76759b849af2a2c6344177cc71614808ab38cadde35f8f803d30020688d421c04fdcd163e40161a3a41b76650e9360e297bb8460165feeb907f00ee44495621f118e5217c0125520f34e0cd20fa9355aca42a19860a974e741a009688eeb0e5ada477cc18ea883874c501cdf151b281bb8daf7f703d5246a20b00946e3b796f90782e66c72ab2b8eb2d093498a3817b1cba149a664ea28494db00bf13b41fe74cfa01850775300c749eff600311ad8f82be010ee560b388febc00879e381839eab6077bcec20c584accbfa8883f28de0af52f768d1d37f51fae00949865dbf2b636b60715081016afb410c5d4e981c542a79ae0e852877f2e63008062f5feb28d5bdeabe24f8839f57ef74ee91cea189e032727cd70beed81b100db3f6eb4d5eb2ac04be27b23a302cb9f4c1493cc43d5bac58a19dd5a45ab9d007ddbe10288c4a145c595c97334052614a99e71dfad113584e40e7ab4435a7a00838b341b4603541320a29452c877286cc06d1ffa73adc68064fe326dad0beb0051b8bde4253e19047a4187d34c8941420d4cd449fd599f7009a13cb4119f15004b4c2d1c3155438147a519241ab7d8ec089b13b8af95b94456667567a8626400cb135c271c79ecb6658945afa0e1bd9fee7feb0b02d7a95584304aa086add00098d72d480cd6e7476f394e083e0a4f05d865af66e27cefe56ad168f08fad2f007a05d1902cbf14a465e0c577f80995f4246dbf28acccd296b8ed7dd00a5f6700ce793d1f78e29bb9f2b990bf422cd48421f5185c5bb18f62a81621b0a17ebc006757a27cf4bc590dfd36b0c79a3b23b09570e2ea57162d01f5b7df9d2c34f300249b76b56d86e09b905329b90b53ff3a8dc2881e37b61782cf168498bf20f60044f2b716b36b1619100bc8c18bc272cce3408e7d4022f9b49ecf68086437ca00c4b2428d7936421cf3197f8a15ef0c746272c92b9ab6c5650a2e055ad557fa00f1952da86dfc4ed3f208f71ce85db777b4fcc8e6cc96f17c295d5903a7454700dbf3c7c22d19c079aa76aa5104e04c4f6e7dbd43b57f3f8cd96301179da27e0066fcdd610bab613b6eae1e2319f20f5202a100b3141d6f670faa423551b3d100866d5a621a3314e0fbeb91493606cf43d24b62e45ebc28b67d22c643c80c9a009ccc85f4c979c4bf210d9a66a6e6086155af3c0238ab37a1921a73a36c22540036b33bd636c26f05629c653a8a2359a785df6ee2b42ff996d778ccd5af344b00cd90c82f86a4330e8878628511f41d8619ba7dce82007ddd7987ff5b91354e00f1224424e2933310e12e558179c31e391741ebb55ed1c73ab859bd903d1ebe0032597c8d96e6c9367f1cdd023915cb55b369f0301c1b46d91f26945faba643003fdff742fc75d7409da27ebc1dd8b063ba6c319f5b5d247bd71f2432ca4a42005fa4ef89d9af93ab92748a96e64f739199cca7379f604ca2399728a7be6f8c00c0ec1cdd8483f5b0ef01d78b02927dd7c7132db0acb37775f217f2c5f3fb520001a6afd4e65d1e7ef93738a771cf1912d3c351d9c7ff4249ffef73ee5855ac009d523700586ce6f6f841fb1ce3abbcf9a3c8caac8f6a494c7a050f46c61ad7008ba5537623299fb3a5cc5c48e83fb725c377a282777a3801148559d6b3531a003ee7f0634ad2a91a9ac44d03198e98dbb77eb29277500d8f1fd1371dfaee5000ca8d9e971c6a98ccd88350962f698e8d5e5846515e334f332297768d17651900cd85c06b3bb32cb934f872cdf4c9e67f82d1f5814c8cde8c74169d9292e98300b0bef65683ae923eb29d390aa7369f257aca6e7bc41b430cb48f6a861e55580045350be6b422f148c3adf552c7cfad5216eb23497bbe75da9843d83abbd4b6004defd8845f1d42fda53e60734e4f8368bcc58a4e0b859ac0545b2754d14b6200b145181642ded950acb499d30314522a9dbe4e8f95795912397751c5bc138c000bc00569e5b3dcb27328f4eab4928c845e053d5bb7866c2bcbe7f38b7d3303004990c5a78215c5b20769d41890c14b04d8cf673fc19c620a675d16fc773b0e000a86b7083c893d7e9acac6ffca31884b633346dc9ae23c6d68d51de2c6f1b5000e38aaf622d1df8afa9f4a1f8f93461acf48ac0280ed8f761d09758e73d8ff007e07feceeb6fe0c0c25103f982166e531131ba640cb4d51c1a5442e0429731008a865abe4388f2082ae38a56cf23ffd00c7c6b7f8608d2e6e400ad7dff4edf0061038d5b67bfb04604e01e8fe7a4232cb19256d989edda1253cd7f2127a6350095b4562cbe5dc364dc51a4e8121f8ccb42821618cb9e94d777d71916412144007d9fedd6250a45cbc9d19e72e8124ad66375b4a17a3abab1ff67602910bfa0007c36e432657e7d1a6461fd2a0e319dd0f21f6704328e5ac846b278fc706083002d229f2292a74306e6ced3f7ecfef3bcdca97716a9535ff6aa5de10db8d79500482a1f76ff5f76ff464fc737e08822a102458ef55142b1381b4924c76f8f94002fdc9966cb657937bdf16fba840ac5d70121c98f17ac7d911627345ed8b0c9001cc9a5de77e4e37d1f616b628a480db7636d087dd3a91d84b03817aa75a8a400be52c62a1de3a67f1869697f83e1619c7870e3103edce06fcb5577eab88f3400e003821fe6c9870469b799b5fc3a7fb2770aae5bf801e64d4318982211393a00ccf09b476cb395a3e8b991c960c7720cf8fd8b25116672fcbacb75e30125d90038b022f552f917b632912451fa766c91e867c2e83e5232e050b645c99cee5600a07293ca4951929b643469f7611270a5ade8d39234491f3a73bb45f34dbaa900a294977c8f2fcb2ec6f5b8eb1c44d76291f8793180218730b665610f5d1165002b39675035faf7b05547109944390301b09f5e4852255ac1e4598141c583ef0083ffd343797fb86e475e77a579ce8aad835be5351e04d35746db572de3cbe8003bb7767e62815de4448c991a785c2ec3d0e6d50f33331f7722c004c903c0d700952f13bb777f1afb6ca12a0031d28989d27aa88adb36c5ce7f6c04227fec71001201d8ed370d1ec015a725be05747167b298528df46517ebbfa569acd43bd000c3b26f443c27043ae3bc4109fa22e1d4ff7fc205013f5938080e1dbc7bfa410041d92232174cc7327d3a48230d82df630420dec7a448ae8afcefa3f245bbf80077c488e4f094cdb0a18780c39fd431376d10efaec13e2cff0247a3b9c62a5a004130d945abddf3a00bf787e80c876f216c4f912ed12ee46e477a967e7212fa00dd3ab68a30983ebb066f777e9cf41510740841e88e7e3a5528a416bd18771700ce7e4891c0e63ad45582332d68fc67d675c8d5e3395e991cbd182b7758ffa80046a6fd0114879c281311d0d0e4847770e98b905ab5b1e1a69756d325ab137100bd807ed11bdd72af9fc4153d5b18dbdea8e4b8ed0f8b2a9bc3ade7512a364e00e2929595256e2ce1ea4f2e5bd871057a25902dbdebe5a73688bb8bd55cec9200f02be0af806d871f2259d71d5049a8f9368c491b3daebab92cd084c0d65bfc00ceed48fcb4a2e2593ca0cdcf3083b9a8ca40cbc6628aabd47149d37f2d919f0034162251d8b7420c3116fd85b5802550474fe57d027c3ce18224fd65c1ca670001b963aea16b644b963c56269a0879d7fbbfb399dc46c75adc12dedb2fa912007ae384916f5f3247489028897cd4f57138d6ed2c9944b036f7cc95d63fae7a00547ac84183127daf3b8d479bb3458077094558961707fcd381a2c7bbe54acc00228a7767e40acc0323f9ff3c534a562fdff89766795ec5fed3d8b0b6eacfc000d28cfaae8fa5066770e254e822e461846f04bd09e609dab927235cee4ab44d0022fcac99e53b8fc881c9e8ed7e41c377408d370fabb4c26f82de7c2608caf000fed4bca7e69fb404d2652c4b45329a7c7bab8da4c5e4c8028f04a53ce6775800cc084724c838311d2fa0972c57e0b419d44e4a3d1462dbbf369f4e1b5eaf95008404568ec258ae4d4886d39d55eecc3370944112a6e6fa7676d6d9b1040baa000085c62c829b191915b45c539d35249966e7c8b46538373e38ff7a860696d30025752b4559ce16604eaa2a95d5c33366c0b85abd294438f2c03f6bae2356be00a240ac325161381a218df25477918ff232514e5c057308f199792829de2398002fcc8e8122d3ebca2b64d9fb1e214f561bcd7e56f2fc16e91a8337dfc3360e00ab138c6a53bb30fa4a8e97c30f07a3b558a27a673a2b7741551d847b51c4030089d894cf1ea84b0a3948819578cbeae446cb93cab6e5b1ddf7a67d63dc5e9700bc618a510327af11d57a482fc69f526a3a4d1a47ddf21e2ce3b3c11225989d00164c9c4d2d59f52cfd5672f44ec77bb5d6a9f9b24018301cab853fc798e2a7004256f46df7524b4b67cf27dac450385d4e682e0ab3a80516c868cd94cf2d9f00a7bcf97df4c53b0e1edf9001173f37e6fb08b45d9104c8024b2d30b6cbdeda00673d7df6fb97b4bb02585eaab115f05756f6f0579a3144b9a398f1ac00613d0067d7fa1f53b87313949a5d435c25a39e88969eb84e8cbcfdfb88666d96657200faa30855951cb507cc513b4f67601f656ed579e18a95495b9d1afcb66ac412008fdc472724b09193499a8889bfb761b27c20097e1a0e1095028c3ea2c2151c0032d975a6056d16f702decd003152079a09696829583294aeaf02fa68d14de80007f4c0d590674d546c5f9bf7c66f25da1af0aea2b29477873eea66aecdaf0600c63b136a23ce939a37a269a4175c4e11f090b778c9b45e852e60a55b9e67df000e4aee7971a2b14d5955e923e4790f1cf8b28939a8426650e84e34484f1e07003bbebbbe6d4e6a1ab526cf5df16064571fd2b2129e8e81464fe488f1d2b468006ac5de9492b937d33bc92244b6564a07cfefd4d34342dc24af7e738f8d73f50068e9961a6b07c1272f8cfc398c8ad67825b74e2653feaf61c54f075a6b11ba006dad26c88fa1bfef1f81dd5d4c8484bd294617fdfc9e1ebd584be7b8ad15cd00e496a2f368ef848d5dddb6cf1441f143c253128ed713ff0cffd08afef83b36008cdaf76a46f05164a381a8c51bc6a7349418be07d15042d3158456f77fffe800c536fd1fdaf769a1de33e762a2b9255d1bb4f3a52398e700243dcb27dc5177002d5db19d398fcaf123930df11acf23e2b0061587e3924673b1b5d56b2097f10010bc3fcc2edc12637eafd6089cb7632d05bf6dc6f6a7e20fd58f191c1e57c10086612433efe376b5867c9fdfacd90c47cbadf94989594d8ed992d5f50b50880061bd0da51673efb49d3a2635ece624dd16004d094c1c547aeb3d3c6278dad9009649b184a9fa57498b7c79b8f9a55d58c3dc93084db28e678cb9a68e3d2ac80026b6a6db0669997d3684abe45cb48cdbd2c7e97bac2b87e9b37c65e171bac300179b7fbe103e1c3ed3cd1ded5e4418b206286362b3cfed8ea5201e1db9ab9400bb7ca397d08983024fccc1440a72dc1d5d09b0ac9607db42102826850ef61400bd38ec190bb3a9648c9ea72550f5db92892418b53783bff5bfd673243dc37000a7630d62fa02eca2c7e4309bc83738ed2db24e52d6846a0282902caa99a6fe00e1f0bb61e129a94af80e6b7528a4c6afe9940722a5523c510569a016f02a9b00b56112d15afd09cbac234ed66f7c9999b62906592f820cbd98265ee242729f00ea91a307e89d7580fd9f97ce6d8fa6243a029bc7da37e8cf95c4c8e373482300ae69a56a2aac9d80b0e4965f653d7749a2c61566e898b67058115c31990074005ead126e5b2ec730081d1c80f2a8b61bdeb8b24e8f49990d968313b9daed5c008c4dab36d75ea07c1907ff9feacdea64f98d6fb34d50f25b9adfebfb3d851a0006603d0476de1005e99922398206aeb32326b2b271ee679395fcf1d2144c0e00d4d87adfd918071cd75ef700993ec7b117a57345e664d943e1f1721ca26bff008b6580a163058248ba9b99c46ec319a13c3da3521f575707bb3b057b060c940044005de19a987e33dbed9830f57c12270125de4f3e3c4ad3b63313082d57a30073e51c5b966da26170ffea1188134f097e696be76c2dbbe0be47e77398ba1a00e083f98a1a49a7e3caf4b8a830e46ea674944756ced524b890530c1a45ec00006c640d3e8319d35c6a1cae555ff632c8115196455e086a92a6243c29af4f8200cdc40fcebcb28279eb5c32097de9f403ba30e081610af1283f2b3ed09b3c700000b5e3aeeb87989f9112d7718fb9bf854a2dd842b9225b7d77b368385b501900fa505de3df0e3258a3cc7aed957fedcdf279170c661f9c8d3f64738ee44d0200125a768750d75de216964205937ed4d02a053b1e8f7ee7d52425d6cc119de90030a3c181fcf8f89a668dc2ae3c54a018307aa1b9018df2127e1ef1c97a099100132b836df90988091b9ed111f30868ebdefe08485ab0eb6381ef0c6fef27f300b83cfb483a1f9be2cc04e334ad84a69b8c5acbb260e92ec4d06a9a81681dbf007fe075430e382cd1507e168ccf193c59732d96ea97cd0a5dec3f05e8fcf60e008a4272f7dcf5770a23be5e8b1b6e99a62781e3aa407ee1f938bbb84935d3cc0059e004144b6782df6033a7e7569d655e8b30190a8898406c05f50a3b08caac00f2689461e21eec7abd2b1d319fd2a56eda302002b100d829a61a32b18b916a0033b5738d7556d71523cc9063262dcc50fc82be43f4cf01f308f6c9dfdfc521002e08a9c12bd7d485956f55bc26e6fe30b0235fe94d5d0b981104dae168a976001ec3b9239d9f501f344365852544dd28972f7b513e818239eabe394e81374500e31868c7ffbc8b59c9be5514245bf16ae48d0b85c35661e4cdbad0652c6744002169480fb70a43f77d372d0f769fd13fbedaf1daf662d541bbfe1e2d340fa3007a6dbab35e2a97a33b006f0f854ad9ef46516ae492d2082bb7c46a055ab10b001f29293c9c84f059bb7120ca9a9f5a22cbe4771de3eb31f6ff778a18b62d9800118d8426954499a20aa16a15b370c22bf8f4b290aae2de5b0ce86881b8902100408f53cd4c17756162eda56836a147bd0078f5da4d9d765c94f7d4e6452d2b00bc011b8be1b9e813ef16676040383e30fa079909efb1af708189ca366fcf5c000a940f930e70a1d2c4cef4f2bdf37934393106dbcea5c3fc736b3cb035b2c400699ad40bbcb2d6a8cce103c7c2f404b4f2985ba966cf1a1b31f24e8d97132400fd9ec20165846c499cfd5c8ad947a190d2eb3ca1b589c3a307e588b2cfef4c00bceaa810ad87ba08a50d8218c3634243412de121c1e5a57ee59fd986e61a6900d5ff86604c342561f6585e9d1e3c3e621f02910c173e7d9008842d660c52d800f654c114ddad848af9a6195c1fe2726f33b9dedfd0b82564df48bca9a56cec008e214a76ec820db879727e61315af572253ae678e5ce8832e539050406461b00a2d2792d3afbf59eb82f8094066627694e787fc991013101f3d232f495e36a0035db05450bf368796838e58fcbbfb343244566f039e6ba294df632d2938f680011e660557f630f3be24ec794f81483110903787374d54393b6dc7a0d31214f00146bf53809f0459e4088f8b273dfba48dcd09b64241a38c321ef1f2106928a00fb2c08c42d00d942e22c465a237a41087774a090c2a792d48e907dc24263a400463f5c4c28b4e8d8c02f9a69c938679c6db8734123a1ed865760d8d0fadcbb001f44e2105a0eab08433ef6858ca78db94e938882efcebc6978fbb8c38cb1c200e953ce6b766608587b1e80c1f8bfa41c91cee9c4e0784c93c274cb1461223200f23ac04e9e16f07ce086e92fd1986532eb31957b9dfba0539b121a488506a7000ae0a8adba46e493289eb384dbd2a64cc6ef7348b649e292ac24c8094e572e009d485ac5bf2ef61f3fdab3a884d965930da48e96dfece4bdf658c6628db37300af31783637e938f172bea0ff32d75b22cedf35e15d56d44bf014a0995f5b1e0031b41b82e0874d9e75b7632ef9c9ceba1f2b2dcdc3640a6354402b4dd9cbdc007f47db89a9554d038c26bd8e1e840964d11b30f0d43d7b1ba0f5f16c5ed1f900fe2f0cd4006809115f1092eacd86afc6c8cdf5ddd8a5ff97d4d4f1b08b2481008804afbd5de6931604b0ed2ec2cf74360911d305220a40a843bfc925d3bd01000acec5cd78e8f1d78c08246e0ae12bf566eed2703fc878ebe2b7191a5336d3003dbdf829b036a309235f7a76ebe4ac9151350b2121352cc3a6e3ee26f2e34700c2d0facb9f88ca57e891d4de992026c0e77bc5596912f6779b4eb55b19969c006c4a033b9daf54e2dcfa0a3f36094bf1cbadc3d2e9967da0fcff3187875ae500cf9a548226072d5564c0b3694e7412b6cbd64ecff80b5c05763b022aac3999001041313fe36ac027f8f3256898f5cb82bc18cba9c4c2d778c5760d8bc6ca6000236edf970dd62ece5ae53afe53e9959089f8cdfd753047b2852475f6cd679100d95795c5915515a58631e6e280708c8f8084044da69d8518b45917a88f70bd0013ff042b4dab371760577427aa459fccf4fcfb96726765e9aa225bae50eacf00a327c08fc397030c602cbcaff600f8345398f6e874b1f3a00501817249ce28004e8273393247996c62d0999b598c63eee77e21977ae5e3f77cb501b2071b5100c721f16ef37b175100cd6f01526865d249549c950832c223550e67cd6a45e600b2bea195023b7b3cd2ba5fa8e47bae5365b2de11dd0a29f4ea0f572e73b2d7000c3ccb97ad0d59bbb4c5d3bb5797a23388b74673190b7362a2b1b921cb3dca00bf79af1ad2aab95b733ae9ab2907d8bb63c9c1a54b35fc69bc693bd96c949500e99adb3227b05db578210d31d0365db042305ed9aaab41cf5343eedeae358c0053d6d76723cd3312f5e9c9e4cdebc069b72817f3eb9412c3026d63d92cb8f800c26ee91baa31129cc6ac8d63e885f56b714ef0aeb125ae3a2a90b4f70d0398000241bb9e4e7235812d2f614ac9aed4851d28ab7177738708a7519e7fb6504000e8ad837402820afc8234c2d964e97439f8882e023a58e48dee937cc17befb3004850c093d00a090a5ff0873d964edcd2ebd2766c8457810e1807a21e77a56700a2412278d4b69a522d776c36cdef25634181e08610ce0369988f04dc56cbf100ab43d52852d3558ee0f803873321c60252ecf6ebf6b61d3330f37be36d7f980047a443a129e63bef534b332c54e02170718bcc167b379573095998878881a0005f1343b8605da832a66527ad6a404ee425fdcf9e9aab7af29b514a63d755ea009435b0a59469bae315e4c8dfcbca3bb9cd2f0b0cae53b4b157d3081f3e6d800065abf580233b1ca40d75ae87fc5885210cfbf4e7990a220ca973fa9e04b5950031762c237d22f6b3f4446b3e0c54c9e5d9803f418df15ebda7f467ad3abbed00a2e7886a989eea407dd14b2f175b3fc07536c982fa9234cac7efbace319d1d002d7329164fdb96de3aeb42aeacaa3b836ad7bcf4fb89b1a99ff62af74fe8af00363c802d056897f164fd7f07f304682b1feae32e8fa03624fa899c355b15e800bfde0d0f939c7ebbd58468e4bcc5284fb836c66e8c4eb9b963fc3fa6896d5900d30b14369b8f7bd80abb932770da892b2a6785039d78b092335fc786fdace700da5a5d40463b6100e75564aabf1739fbea735079790c16315094f1c66444a700cbdb50dd9dc0cca358055f0901b614c72d35630a5af82812487bf80d6ae0c40015199e93625c0a330501a6bae57250d0dbcb4959d111de34f006297bb05171002368e75bbb5170c148ae2b2a24a20922c494d93acf79cba3b9d55a6ef4abc700cb8e23721398c33124b0456f88f592c9c8860e3b30bcc608aa71f7ff25c91600d42dbb85d15966be9138178bce6990e28443bda2cc81226a167ecfe7095b3c009c765c11273d17ad473a32cd064f53fed1fef387f72efad3ea35241a28c88000007f5bdecc9db1fcddcd4fe40352ca9a73a520f6561442430f895f5c66cae90019e4eaac378a07dfa71326d740dad9b2ef0264cba9ad52592cdd5e8a1f2993005bf6c16d850f22b7b8409882bae38eb42d060045e70a78dcd3875b3f79184700cc2b82fe6f77a0f600dc63caddd1834792933799b744f73092af12f452da0f007378203ee21ae85e4929f0ba104d045652a6847f8e9d9e330389a5bdac432000976395e7a7bfaa5b37e926560f7c1917dfd4dc95ee92f0971595e6366c339000d63c415a4cce9413260a8bb9b9ec2d3d9b263d07fe2520977dfcc00c19897d0057cb6f9a70cce3378ffb3085de6baf7865c5a15fe1c58096a8ae6ebe3ff6620080f6752524b0e122c5898376ea9d35fe396f0c7514e90decff7c80cd6156d600d1bc0ff9f5b60ac6b4d1d9516de1fef899e76dd5dd04130b2b4f92b5ac84c4003afebc3023c34d3f83bbd28da873d8b917440d306b7ef70c3a3a3326347f660017bc3e2b54b000bf03a675e49038fa7c73df3418c05865bcf2712ff71c754600fa786c1027a896f34f52e684a580e84c32c4a7294616d0be82f02459bea9a500feac53f439c08ba70bd19a2036f8d30ce1b6c8539ed0a946ad4a7e00b2dee800ef1437d34ff9d6f673ac6547cdb0ff6868000c9db88d9cfadb9bf08a610fd200c3535753f4e386b08ca40c1ce45a267731398bfa3a45e82b3fc5af199d7af100a6ae53a5d5abd6ce544ceab8581a069760b75c078a17dbadd07751c7e52eba004b85bea2715a289372648aa18593ae981843b6808b5064acd280403a488baf00e17380bf5f84a31bcaccefc77c1bb582f4f2d84931ad90294595c9cdae294b007a3f79757fbb75ac0e906dab1b2969f7648f2699adf9593b1c93b28901b3c200348ab9a5dca5bf021c0b23246444f10ff429ef7eba21bea22f461e1e2ba43f009d158136a4c097910b92bddf0627b8264baf82b1bd60235299849384f7cff6009a0a60f4854c0d1a9b259ef0fbb04c49cd7fdf8f7adab7274c8c4549d76fe700c72edc26b9ea4a3aba10edf0ebeb20a3a89bde53d46852d5e579ab61ea519c009b12a4cf4edad45c6469bb4ce673b648835db25b6b41240e95f33b4fadcc6b0005e8899b5bd70239d70b196aa8e96339fc43cc2ae33855881a7a2ff71d0a13007a87d1f9dbc28e352267c11f715b5b587f336e74ce95e1cf1a5fb2e0177c7d00409039806811698a154be49a9b8e4bf50a40eba7f2cb52afaadd9e7aa2973200478b5a95efea4c7809835faf761485fbe002f6adaf1d8f5c9042cb133100ea0002582b231860a63e98699fc9230de20d681c3b749182a036f4be51eeb0a9f900b6bc7dbd86f41022b8673efed1b28a910535c163a3b1ac9db99d902813813000b45d6d98f53b921014118d9cd56f070c540a033d5a6eeb542893fa21aa6440009b2c36b89f6cd07f370dc5f86844866cebad695e2a8085302d95c52559aa2300dc438f8be1b171b8725534f4107b4aa35bd768820c77a8461c41ae2c070f6b007f181aef49d3cf843742cb8b4ac7a93247378a76175fc49685e6ae73f6216f004287c4f115409bfba6482de22b157e3353ae3df967afd9a00487fec758b2e600cae811a8348de5e03812d8ec26e1decf39be638e9ef139d87cc3fab388d0a900a8fbc23fc7d3568715acbf7e58a24c7843b9aa1994448226e2c49eece9a24f007846254953564af74ac314e791125e58d693fbb775051cc462d3645f8bb368004690d892fc2464e46a702bd01f2551ee01fdda5fb3609d8889fd897c0cee7c00337ab8a92fe1a4973854d64a02bc8809a3041291b6ccbd144a46b6a06bb36e00450fb8777b499ae7922d44c8aeda75ff1c51d0b644db6b84066fae38b579d5008122dd93dda2f15a1a9d9fe27fa0fd6548bea068096a7ff1b26f72af0dff1000da986e16737f589f7ffece4d192a7a547569c814340589111b0c8ada89e7ea00caa01a137b7db4f92a52738e2c2207f8d844dfb04d46e91d40b5a2cc6315f200c9c0ea7b591200f5cf127a521cb81c24f0b373a7ceb712c82a0c7ee3c440bf0052fd39dfcae8c6111127b7d12c0a0851f265d190bc972254611e59281a7df200f2d679f0cd2dcfd355aa10701f5122d837bacd4802673a3f886a842477d07a00701b5fc14eaebb0157ea68d8e4218a94afb6782a5871f914feaa0c76a8fce400dafe689e0585872c6ee46b077427cd41c455723ed097aee625a6ca6ef3d11200f5fc47a7f687583ebb082cc6e44f1d448cba58b945af35a895185e0f8c5547007be046ca9764658b48c60978ce136697d7ef85bce4596418f9bafa09488c62004a0779bd2d2ec596dd82fc98f016ff807e7da41124038bdeef1e28dfdfc68f003f0d766cda381c8f5bf8ca56f10a2c9e023d74c872ac5cc9a3891db660d23800d56d0f9d301f0f51fbd31d3e4e26bca9919abcb4b1b64d8bf57b1a38e744d200dab4d41aff80645e2711f3582808cda567486edc3967c85d405cc12c60b5fa0029223165825e34b6ccf16e6842c607baf25652215983a3480bb2d562b23f8d00b48b3bcffce03e83817f697f692a0c5aaf44a976b8513ed7583bd5fb17e92a00bab5d4fe6328fe69c087a6c885909c43d637e3a0888b86c40f380a84dfef5c005ab4d848239ea1a578d7c919929fb6a6808757889a1831f560448eaebc681100a0677fed523e0a8c468910fe5112bb0f50b46399484b72c0a2122859e240b300d1aebc17eebafac33ba1ab0d8825d17dd5b90ae948cf59184e60be45c43ea3002617bb2be66fd97a3b31a90b71ecde0ae40e4ceb6ca6c168c5190f5d70ae3e006efa93bce6d0de77b28df279a66d5fb4b5ff80550e26e73787f9e8776f7c4b0048828738053dfdfe9f199042a7d81e5e1508c9fb871cd3621b2f419d4cf2a50011ee01083a59232ae8be259f136d7dfcf3b24215f006e9f43aaf6e26b96cd80091d998e6a8498fdc23a7ba87850cc1cbab56a5380f080e88a825c25e459fdb004fcafae71c066a3aac7f43f8638911286a215f52c777b63c860cd7ae1f8e2400ee7070030461e8de409b94ae59345a22bd195089d0ce753b53bb14c5d5828900f4524706c4aa4e2f114eb730b3a3dfe8c800d316a234f95b21e09ff9849ad1008d2959fb7b3171c476c8e03c72addef4de636a8ee7f91e7f50e5a697e6cbe0005b343dc9885882a2e727516613547319742b76659032f78d99a171f02977ac000676fe8ba3def5e01209bd9fb6488eee3251f15865eb1ced75a34d2f00e8290097ad22a4eaadd1c0f612bed8b9662d1bf3dc0f512eff9e42f70b1a93cf3307002df57fa0448ec6427ff29a58f493fd9e8e3921af54de763de5c134ed97aa6500d6827f59829b6a47d2a4a297047ed3e3afeb17acdddcbc2b8a30f9cf8bfcb30049c083cc4d482c0c3aa6714bdcd9476d1466add59db149d393f44565fbd762000cfdf2c0275fc318e7cd727437cfd7778008ba86c996fdf872387568e6842d00f4dbca83701042902a696bec4ac99ce7f8b99c38b3df29f2e9e1f8a5003646001e75e79aaea8926c970b4c8dec0cdc19b7f34d23dc314bfbd7c0dcc4e88a2d005620b1e79caad9e08a5490abe6beb6ccc566be5fc5b8ca5bc32b88e10a8cac00ac880df8c4996cf3ee1cb82d3d035d4703a0ab6c83cf846eb8389d0a2465250017acf53cd70396e8ff17ce21fdc9f1f3987e4062e946b5fffa1cda30119cc7002a310b3edf6da39e0dd0d29ddc8aa841dbeb1cbaf7b7e6a00bb4bce0eda45500421b82db22d0e822ca5f80daf81d29c044a432756822ccc3b4153c46fe5b4b008b1404ac87edc6d77c328cc17bf11d67ee44c984b85359f5f79a218350a14500d7f901ac07e3fbd4db765e9b6beabe6f2ec9e0d3bfe619445b9f1d6d5bdb6300603cdf9e6266146f329a0459a1dab8663f6b2db76de66830e986948c21ed18003cee2b4b4061d116237fa30d9db1e19ada5facf8e147a2b6f95232bf3f3cf100b47c04b51ae962f53aec4d1ffa271ee70252fafe4ef6513838d17f508bffdd00cc0cf401fd5dd5c608fe873648c46ea5186a3baefe08cc4357e314888eecee00e9fb7f67c4b6ad39bbe03b6f409d53895adb0c9f0c016e3467ee2174e8a06f006e1aae5120400acdff78fdbe8d905064e6250d807a6e93bcf78d5fb07880dc0005d00a66be304c978ca1519807268ca71356512e2bb3a5103af31095afefa500459fbaaab4f1d05f813e1727c7adcb080273619a0cc114245f280476994dcc00f3bb541d6bcd8eae3de0598992143e698decc384d2883a8c23111bc4d5de32004d8800af45a4d28af6c0710b32b8600a095b3ac98c96d33ef5fd15ec730e9d00b474890f3f494be0244e42c0317d619fee8e98973f347cb584b19513cdf171001e001e9854cced02075a8967ac7250f0cb3fa30fb226595ffc36828cb67b340071d6580960fc12628e255d5625c0d118125d86a032c55551f8659a60afcaeb00654c3bf74c6896c6aad15535c0f5240274116575877461d7fbbc6438fcc64b000cd1a783e250f5ee420d396a5a8f3f3c3ad6a9bdaf5329b18aedc46c72ffa9005cd59f24f21484413302029248848bea32b600661e37e105ed74a7c949cce1007c775655aaf581ba63d2eb0ba82cf058c9fe990e215febe10f232c75d5dd5b000b869a4875d4671260163d920905164e35f3e942b4c2134b6a6e8accbe522500b5c33aa7a42e6317ae81a17422c11d957d6b439c7ca062070a4896df13aece005ed12eed30ec973cefa3f5eec35e25cb296cbc5bbdfde7671e2d586a80b78c00e3bf1ea8306a426015b1615f6e53fdcfac9feecf9b140af9e74c488d0c87f4003e08527d8329f7b6c09b276d1cf77e5eacc25484f0e2f80fb5c66429c427b9000e600cf984d593c77df2798b81cb89ea5a7a3f78dfb8f13e7257cf634bc96c003dd163f776f395e45cd7019b966a0cf56adaf16bf682360f616a16831c827c00009fe6ee49738a232fbdc2ef9235257b3d71894b36a152b738e3ba761647140097752ba9d597328dd3cf081d9f92cce63217647059a3c8feb179dd4a837d8f001a9d66fca8e9c8729a8b13ac77efae10a2d782ef5a9652fe5e8e5a1b99413000660cebe01cad6de785cc5aed0fbb1fe12763ef56842bb56d0ffb62c4a308c200ca64d1be2a7a8a4fbb5fe1bbbb42fa77e63894a49e9c91bb690670c75a2f0d0043f5dda246fb8c9793d79208a8f2c57e729c91b62b9ae17e59328e703a050d004924e0522d56590a3049c575dbfabb20ca97b9ec6c9fff4e7f7d8b837681fe001465023304656a177244a7a60ca754d2a783123d2d8661cb82301fad238bec00cbb90592f4606f9e55580be5d1ad6f6400647a921cee4c632bb483aef143fc00727cf1d6315cb105285071671307fb32d86268a0f9af94bb867566f26ec67d00d482ee79fe33616458fc76b4a964c30a02011034771ae075a1af2020fcbcbc007aeac179005749116dd23b487e048ce2d8f7bb2dda73b24a072b140635882200e98c8e9c9721a764cfecd862aee0ac1f01e06bde26b1bce13fbf35e523a52a000102f8d1a5779062bd630bd3e6334ad9ec1034b8b38bb7186a90ae45458e910051eac0123aaeadd54889a28a29bf8f277bce452237d33bc7b7c608804f022b00cbb4f803f5616efbab44963112a87bc81202515078278916b68b59ed54a72a00dc16cdd7c5d65282a90eede66e966a128276b4ec63299c640d7529f9ac554000900fb749a0595e01165713fe4345a79d250a204693e01d98a7f4b7fa0fcd0800dec6bd01940b7d084d8d42a9473b516cf1aa011c51ea694e54316db65b6f13003e5b8355ba62323708f04ca6793b954f29d686ec7163759ac6f0227ae2de8a00638cfe36f2c4c4b51bc87589e79fe80be5857ac54cb97aad492b960caa66e100ad1026eb68a5eca5b731b6c64cdf55a07608b6ca8ea1db9475f1c459cc317f0065f8179ee41263a3b721c4598c564df0320d2077810e74a21edb140c0b3cd400628b7fd2303ada23dde022c29b8c7b36223b6666490c563add93a95f26681d007f27e5d3b5e1e947dc54bc0762169a8c1ac9d5dec7b5bbd658d703618e97120018e9472a05a77542a5569fbbecceb4243cb81fba6c5fbb0d89339afb17d01f00067dbecbba96f1eb2354d5ecf4827ade14166f48b820fe0bf82a48d8d85b3f00c321cffe0241b779afba1cde935437beafd0978d80ffb4d91eec0b3c5511a900dedee4cb368a677855ab6e7bf9cb111eb4a78eeb69f26412ef2c594559985f00e7a7de4e8ff972f5240b2794c2c0b7f0b0817d91dd98f6a664bff2882ad53a000f3b53f41fb1e03185c1ee03e36aaffd4df26883fae1164c5d09768be704f000ddb606860d0aeeb3cd35a709ac4456f48f56e211e42b73bb970f4e80673bc10034c4600a33682ce2e9f420c686393dea87b0347763dc0fde3745059f87434100d1dc38799e1fd9d10343a06bf3cfc8f6b48c5c3377dae2fc404891d044825600ec447ed8ea5d00eb9594cc3157d56c5e7f2380146a952387d6ece86c72b674003eec400c4dced873820c9f73d419a3b279a6ae0a8b4e2474cca4541f059b4800e3495e90c8c87ef1568aeaae6a980e9b0143ea30fecd67d7691aa631e04479007c72b523dfdfa223b39293933ceeaa461d518a9c48d089897c52e01bbffcdf003d79f20b1d74789aaeac9deec2189f21b2417233b5bbfdb77513db1eb3d47200a5420effafdf2aa501f409da602186fa961d4c3d3c50070ebaa0110f212758009a5c1a563d7210dbd9fae9a9b736f9c9aeb402e310eb4e8bb3567eb75ed65b00deec4d6ddc9a99f1efbd75c3e8806b02a6d799c7dc1f5cbcc0661acd948e6400623ec8c5777cd0ad19de53c9ec83df9a8b3d6166cbc82221226c4bc72f5a720049d8de26f456805472b180b3a4baae70f566e29e245b3ba7ab471ee7e963e70023b2bdbc163237d3659a69f75d748f78a379cbfc7c76652ca1ad115eded2e100108de463768f1716367d7a7b57b6b48b632f85b1ace8751900e9107fc3432d00e4b5095f4216d19ac2ff3d17ed1e4a8ee18393110b322001c7229934c7f2fc00cbf0d89502707b33dd7a9367c440fa557b80abd711b449f556f03dc24727f900d116681ff3fb89902ee86cad7a180ed56857a52feeddb38617aa9f569d81880020837adcb1af02500cbd40824085a7ce423867eb1c71e9e74844a49be3d96c00d99d68aac9ca105d2ba67c035c72ae4aa2e38acf4e34224852834251bef04a0037ef4e785689ee6794a359e9330ae9e2936273af29ff1830031ddf7af31707001b8419fa85782bfcd069ec558678d63d2fdfc92322865230babda986bd0a34002e83657894488c28801ea6d6080b68b43a0f4b1924c65ba258e6653578eb53001796ecc71ec3319f05de1edc67ada4aac307735c61eb6a3cc9cedb17f16aa00043ebcf2b67c0cad58c483bca5deccef49cdac710eac958a53de5a6ab7deb5d00233532d6b8b0fd8432786f29ceddf44798a3a7cd309eed13ec0f114c4e475500b0aad69b3c2afebf31f59b873470c49570df21d84383ba797ee34f9f0d4e5c004790010fb7cf8cecaedb2c4d115e9aab4f243e835c6fd468b2a9da2f5fb8a2003d6d883edd349ff8077640c9aa92b4898c867fc462602f287e2e4f8e913d2f004bf4499ada2c4780c84095f4ea7fb7c83b58b547e7536ccfb5ff102ee212b1000ec756d330698865c67b64422be1ea054f3f1fb2993fb0c99acec6a460890000f278913519573ef1174d17c8553f5906ac254abf75ba28c9fa84f89e1c9f7b0083e5790ffaf35da604745e35886cb933f7863048b88809ace8430039877688006ca865105881d19ef60450add7d1f785896a5f113f9223f94bb3f2e9e910a200b43fe23609f6e7fcd00e9498c625a4358dc1335bb82c641e42e4c914f538cf009356d3940fb148cb6359945f544c3bc2f204ce969a81df7a26fa3b5b70b20f00f8b50f5bdac6ea4d6e71b0bf00fdb47770cde56dfdb8866daba0dc0a761156008ffbaa6457c000268fa0b1a259dd1ae85e3b3b9bc06570d31ca0ddd2c7a9540037fd0764be4f146b6f8e0ab8a003693c23c49313aa31155addb391cba7cdfa0094beb8127edafaa0b9e8e8f646e1b5334253d10c388b20415300f08bb775d200ee1743d6740f6a6e59b791420e0531d94f5580dc955df38afbe27e6a0952d9005233eef0bc51d61cf715a778adf00cfd425283708a73b9130245bb4579a5c3009c39c3d687930e33a751ff6bcdb6f9192f91b41239a8989117932abb5ed5d00071f183487302342a36620bce61740ba7e8e0cba0408c92b367e60adf611f95004e705266b39ecc58ce12ef8c6240120196ced08324340bdb1ea905d126a791006b149c07712821cbc92282d6778f5d122fef89e5dff1455ff4bb6f68c7b56400bea8b6bdf1f2cf4d2c67a7e3718d1900e5edaaec3bdb9c62afddfec6dde4e000ee3204f13bab6ed43536e411be997846a5a7aaece81d8392c0202e3faa0e8300c25732337ef1a4560c0b35f8da51c1cd7666b791f4796682b4224fd9525403007a665cad122f159f25f0c21c200120e11b070418dc7d5055a63dc32e3deb77002700c8f3e8fe258d137492dafe076184b71a9ea5932d3de28ae7b02e573ecf00b270e5641915bd7e9509012d25c650a17c8a26933a629342d9ad3b64ff13740050d5fe46890c8fddf9d2397a9eec63d409171d987cc3a3a4ef1399aa0be33c0038fc312dc921116d8a36ce12e42bd53cd57d3a98a9ae378aadfcd8dafe2b1800c12243faf2d7850cf7e61c305312530f49ed136e10c86387e895bee0a6b098006c3fda232cdeb710670ca07d6d1f2a55014dd2ed842159db488a7c8d883ec100838f1dddb72aa1f80aa50c2722201b1786ea457a5037c25f1ae1f9b8e59d9700faae579683523d0e769205bb2166f831eeaec68b70beaee32c4266a6dc2be7007bdb8bc0b5e66fd82234831e3f705e36ec32500d0c6931639240ef733b13120092dc08dff8b4cde50bcc7be95b15394896e9ef93a8b52553551871533c026600d65f948d2ee9ded659b732595b572c6d8c1c4879102b81e3ed31ac26019ffb001a97efe434549af355c7099c4442087d073c3ed0070fed03499f7814eadd1c00be3eb87e696296af6e146882434db758d6a90a9bac3d5b99506c5c4c017252001f99c7774d5bff058ebb267b950a4f740513bdbab398f0e5a08a416da28fc4004b4fa0cde1e86f3a9a28b53353f19c7ce99e9ae03b90b89b1f3caf09d3b6fb0016b3a31e89ba4d9af0117935b1d45b4d112fb0a6f672d65671b87a29520ab000a558727ace9880f4480593ec40d44838d45a42297ffc6e69095a2b9139faa400fc7e9acc68cf29638ea95e5c9352f4dca88fb303bc16da976df68258e86cb800bf5c2a59a0a6894c3a57c8c46ccb071dc9cbc4f0571fa48bbd342820b04e34004eb710f4991b7e2e08167e8a4160c9c169d8297fdd3dec10d65c94ffbbae10003dadc21f2750e7e26c4d2d7ae2c9693835581db9dbd4fce8aa5eb77e5ee56d006d8bb4db7e3534f8e1e39b285bc6af47f371877a59315870ffe5961b1e194c007c3b408563a595f3464cfa620bbe1eaa55a4046475ba16ef26ea3e4f3272a400a5ebb2cf75062e96d46c98f27a9bd8a55d00fd7abbeb79d0fe1b53b33709a700aa0781b018aeea7f7e0ae9bd814cfba0940be6b81d373c2e71816e733498c400e235d8c389708051a00a4ff7b8dfda7522bc29af58cda0b640d200f5724bbe0059194eaeee3be327c2993dfc25c74c4ebb14572129bde9607c8413ce61630100393f68a88fce375d6e5b69d8132f04f1a416ab7d00497ad9af35d43cd5073a00db4eda635cca9c84aa69ed4fbf742f73cc5d7a270eb09d712d8c5249bd615600ba55fc3bc1e522291ccd215cc079f862512e7cff84bdd2821552ac5f65c0f100f8752e41961e381c26194901eb5322c97767c19609bcbedf2c1970a8af8c1000973a4a928bcb3e9731b615136ee3d08b32b9e3d52477aab7e7cdd0b43ccd0a00a4aabf9d74ca29b7c20258e592fa977021f34d7a4c32c828851eb76b27b49c0009d9591e578af8fe4a6b86f943ebf6f0382a61cb158195497aaa731836f8420031c9b44a6ba7859a689791a24660ac5f99de573f24299596e6307326f2c9d100d8b5f6a0ee9f577ea2d72cfaae6f66996a31d3ee261d2c15a04bfc62d7a454002fcd52db50550655aaf0022bdbb031511c2b38a441dfb581d155ebfd720510006704aae3437518352be16e2f6a30c84cbc8f53320cd493553b52f341735e450037326bb2259265fd0dfbc01de422449c8588726e66b19604f39b463a87416b008e81c6e4321394f7f6c01b1a697af3c3f4ee499b945d8a10cf1fc476233f4900c86cadd0be72c16f9e5dac30ead1b00caf76ca585d4fdd754a6b3b1ba5405100b9e3c10edc825f309d4b414e6e590a5806be61afe3b58b492ffd0298ab9047006ffe07bbfacf98deb84720ab1cdfbba872802e8b6a03631849aa2675d452f600419a182b708199314bc5ef0475face5f3b6edf8f915a7052cad0adb77bf5ba00e8684ae7f1e75066403b08e5f81f64cdf293178fddbdba9f7f6419e8e351ca00b845f1e01e04bb1bbe7f7ca818a3df16704d375acb21b3900deafae0204231006fd08a6840350cfacdee2576fdcf31da35c9842f75c604e2f1a92ec4439db2001bf07d8f96675c274ad6a10bd4fd9a57a0b5251bbe3c981aef7ffd6e443cb9000165a441b713abe3416432fe03e17de1de8266966d2d361bfae1d2e91ee0ad00d421fbe3880d5accf182f8a9b45928c6d11bef74238ddac612bbe4c5d326680034912577d14bb0675e6ee024237ccf3cbe93cf18f1fee79592f1fedbce37ed00728d371f1ea4efd2d063d368d695e3b867dc0074bd638b2a14424b44acdb38003c2eb07bc9902f3e643ad76f7c374a757a92cadc5f094896aea3b4b65a979800ee09955b033774ec29dd9fd8fc0930d72011a39726c3a7efa33aa59b5fa531008252864c5709ccc7edabc2df37f1a5f7556a9a7405860fbc3c1c78045b879b002a6064d84eaf7ff88c9593a64d45999296e78003a784692777e5e8650c5fca00b7889d4ff4e38221a48bdc740d2f5728f5df53424577289db0b57860aa45bd00b6cb3c7c1087776b738a5dee1f9426bcff240b3131a6d5512ef09d8dc30031002558b4b2c62051dbf094703050947235d351a4cfe9838a914d0402033317dd00157b86bfbb220549db1597726257bbbe8a754be601d3ff2a1d48f1db516b4900c9e2196725dd53537f5abb98deba468c7c57ff79c27faff0101852f7c834b300440b7f42a083d7cf93d3ee3623b3df55a8f7bbeca1a434c39a331b93fac76b00c41dc2135d503999439c4aaf48700c1187378840c05ea339891903c0bdfa610021b1d1beaa3f7d3b73a2b75905c678635d53235d95e62185e58df657f28d54000a7da390d5994ce1496c4240d4dd5b0dfe517a631f24e4e45af0255021efbb009e13feaeb14a7f3ece4af9301df98ba7bf799b713fab0a3bea1e8caefadace004dae3f700eb57aa2df50b71637d27eec29e39d03814e00d5d8d3c0adf3d7640007850d66c2efd6e7e5eecd32277671909970561a81e1dd9d69ee983701d6ee006858782c61cebd145341bfb99abe6bc40c3b6f079c1c0991e98873887201960016d34531d265b0111e3c1afec802f16f7098b299d57e8339c283c8c1b09d3e0040fc51a616735f7c4367182695e23266ef509708f84fec6300e1adc796daa70019436e5bb64cf96f25814e7a742ab4690d01011a482d95f0d001ff3f8fb993003a29048363e93ca296c660e07c72a39bf4bf71775cb1197a774e76bca47d1500c07353afa52733d91fb86a6fddcd8cb9ed3d481a0bfa6d4172dba6b23b6d2900c11944379d728bef9d17bf1d16a622cdf0471e4ebfa273b0f7a10261066f0700f732e7d1b0a66b16ca449b6faba5f1d6729554a8035a6ee02f96ce2aa6183300c4b5758743a267b832aaec8752d67384354b42aff355b8908213879598bef40077c25c8a49eba5e19947df22cd307ffc151848d2e63638d84722b4c5628ffa00b2212f23a59dfd7d5c580a200168bc5618871c6705b3939226bbb8d01d96ff00a6f818928a16288b35315dbd9f8b615cb48a296294f5a3486e413b45f8c8810039f44c92f2e39fb1f309f87a065571db6082e5da132be45d7aa3ed739007de00f25fe72b8c5f5112625d54af111098110ca85a881e136742db614a069b2d5e003bb88e40d11593f28aade0108c61fccf18c85efa83caeaef6f2ded9e624e5300e3b704c6b6130fba83b1ee8c51154e196f0077c2f9f99c0a40204f36c1109f00ac64d4c1662394c9caa46d85626666f7873ef40f24567b849c49cc1e3385ce007fb9e31fc5a1d4bad03b7a5accb5ad73e1e877edb8c42cd159228512b3dad800771a3636c99d5fba13ce99d5408c37adbb77165d288628a16144a37c4d6e1f001cc277864b91384d43504c322bd9e286d21e4a808bacedc846c8d018344f38000a88db1e496e3b240c2af68945096fda7dfc3294d12c7a2954a92175227fe100ace6510974db1cb373b9dcab1bd63bf826e2c0ea6ba7c499fd6add6da6a9200000c206e8466c34a13851ce3fc8b3bc9bdfd58c574ab7e416b3b0731b2e4f640011f0d71070b8b495e8a54e32deefcb678fd190f34edd98109393e82017d4e400c5cde216015b032ed4cc6b6c1e748ddf89a0962f3ec8d6bfa312b9c2d62b46000206ba0624a363f07f1bbcd7d3b64508c930809c9de857e9f55fcc8d3d35de00ae61063472fb6aa0e2e52b97b932b2305d2608f90b07487aab53ec482cc1ab000aeb940dd6721200b7b528de60bf5539f4a8d59631a08e69f530b00f2656da006ac82322a1ed3f2d032219e61ebe949ae7e5a670de33d6b4dbb74e065fd8a800a36f5885d87840906947785494472812c52f4c7d788089b25395400948832100b85e94b971c4b207b7525746c3d649b8559584352ea3efbeb342d7af94a9b800c8350b768825d1d1933e491697a02a8fadba4043e124c0c26ed2b4c9f0d04700b0505dd6bc632f8de3cec161c111d4c78c89885f825f403f7c6e2d5afb36fb0072200dd5f4774d6aa66909958d76ad708c209c2e2501e522e0516616360f4100a9e719b7a8d6145259e6b8d181e177f17f1fd7c34759b1db760a924da6b20500a7d6ef5d49a13fb1444bcdb04107a9bc68194b8378a5d66ec8751c70d4f474009f745b5faffac80398990d10f03e62e90455c99161b23b82b88c98cf414d5e00d1759f1d3708ea02605e0902d416fe7c09de20a9d024a9f4c80149d670bf20000d219ce06ccf75ac3d88729c3354a8627dd720b1dea2fd6aeebda962c53abd0005cdd91a76f7cfbc53159d90326ff5933c9861ab82ea092f51823db7979f1300128b819eacf6d6de49de287ec64c50aa93f7b0509862cde5800f2349c0a37f00d772aec02d67141c9297d4d304e58524a5a5044067cb852a46377da655e0b80041e6a3ff83bf46c7cb95a22d6fbd303b63b8e5b2a23409d19bf86f3625209600e9195780568ac22dd7251ae6a974becb9cb60e80e70c947ba1f1b2c79c516000158955b0988baa45897b157f88d9caf8a3e931b90480a60a512ffb4a930a18003a323c600e0bab34677b628b669d371a1eda48366f6716f9e040852cb0dd5800443aa150bd8854b95366f9e472b94c079e3c2055f78f5580ba43b90f5c3e1c0048c9201bf077f268a30e6cdff7935ef5417ee72c92508431c72986ccc406a6005ce3981f44325841cc8835141d79cfc19efba7e27e9b43b0207a6b70bd15f7008601611badc5955085e940d3f67a5a5cc285b625bd68ff0866aacd277550be00bf297300c1f4cb2ed6ef49d51ce66403ae657c6cc15692242e8957fcc09c90006f479de53f3e810a10062452431060bea2f1d5bf304bbf59b3f0394a1f4a3400a28340d4c762b79feb79d0645a3882555e1caeb5642cdd71fc2e132e5f22240089fd62c6caedd0d43bcc819783ab4d8f5bddf6a482f03b82d01ed9e3db07cc0029d0669137ca70135ab5578d906a999c2a9ac38ad3e0ef9e424153c1fbb45f0026f89f029a3821ab799715bc34be33bdec47a8aed108a5f02a9ffdcfd8818600cf47b23ed3d067a2f8ab288b56f95965cef11c763d10e915341d194483f4380005b9c28cda31b85078c99e591d430da9d94a3635bc69e8bd6b4cfe49e9679500d5d59203b56ef591ff38deaa430cfa36145197b57e70fe8a3220188443df5b007ec2f06e5da73d008b2b43bc19dbca85cc31b49fc5c9f88815dcc7a8ba749f00d10d4fa0d150661e57407e39e2d814f4bc1b45f958f4476aaddcda481f64af00ec726ada5aea2622cbef1c61014246433c081be1ef3976ac31b6cf3b607f3f00e9bb1eeadefe95a900e4dc34be6bfe6c25c25dbeb69df3229996ac780ce099008aae53d3cfa05e46cba97c2e38141ff81c0860679e28ea001a8a15b27596d500236a968b4615fa6042b64b0dfaadc291b8325c65ca03742e061bf6c93dd99c00b4c9e859949c98b6cbb22bae8ee22c6f85905d565e4804b0139d427bba428f005da9ed0451f9f702d9bb4ba35608a9c546c85f7268941d44091aec3cb5b1a7003dd3d80e4a285991d419ce36145fa565ada47e08bd858b3540e62d12d598e90075ff37c873020682b66f081c92c039565bfff790ee7f4e79eae661a5a599ac007f5a4c0392b5fb1576e2355e7affdede6a77a76e0b280b0c0c1a297093f2d5008dac6c540a8d68ea0a25404402bc02028af652a143ed1b0eae2deef9cc7323005cd819670ad648b0c36f36794cd1aeea901f8ae9c868733a5c90af90776b1f00d542094d757ad3b20c8251441cecb864d49fdb50772e65a717b3d03b2fb51c002d8099b0886a26e77d35ba09dcaf4d32dc7433871581efc7ae8d2f3e1ec6520055ef769c226f6456fe9327745f098949b28c5e232294ee2bc033ef7b8f628100c382d599ea5072391875f99c929d3edf4c59aa0fd9d6073df3de541cb4f654007c15d16297d81b07ac3ec0b58b14498c4cb83f63feaaeaa3744581c88f5dfe00651c5ccc32fdd6abb0fab07d0c9f11583f60923b986ad5058d894c37c770c900e108298d3ea0ba5d995c9dabedfa3977be02705c499eb393dcf287f51cc8d500d9d758acd165308a9aec1a8c509f84d27bb8496a94db438864e1b9d1c6a6ab00d2de80dc01462e885278f04b8656afce0ba9d87cf7558c8356be2143ae8dcc00a0ee1673078b83b21d19c961334695ec17f57cb2b870b662f29af55176d92a004f4bee8324fc7a5a08ec63cd45bbab74a190461fecc47d9813cd0a0e2666ea0038a71419cffbd65dba6879e68811aeb2ec88fff92016f8081542d3b8050ae900fe41937bf9b42f14eee1edbd25dc123c73fa0e70362b3b28e6818322f791d1000efc16d9c6bbf72c812b51eee488b621496d3cd61c8d36dd659eb1f950ead300a00b89c3d60eaa178d7595a6aedd784f2d8d32ebd123f2bc3c4b2c384276f300026cb24975c44b9249596c2a9e8b0864990ed8c5f4ed5a8faf7275f5878774009347b66fd34130f8520901850a178e3058620958a410d6f789b297dc861f1800aad71aed6b5a2e915462123a83eec950b2176ace5d1d9f78306e799a3d9c6c0050a369ee230aad30bc1f6778b4bcbd7f263ec7ae526cf482451b6a8c7b3935005748edf89221041acc92955dd602eeba1e0e947c851d4af07271e86086fe9c00be8da12c772b9d85b44ada0170c1cff6ed2d5f3a8c44019e877abf7f3f9363000de45bc279349cca50b38f65aee06c57163fda50e5241dff5860811adc6b9000b386303bb1e3ee1a0a6ee1afed33f2da48594527a51ef85ef98db95f0bf23100b483bb38a4ff4e19d77fcded10d5da0414df13bf42f4a0e400f3c68d6aa44c006838d6b70da2056a0fa34f9844af031ead211f67b01089045c952ca8a28904001715dd5174b2a34234596024013ff319cddc77fc78bd1d318a956eae7db02a00f5a51109888475abeae2d0a71b61ab515d292e29563d35b9a8d7cc4b63e5a300318f96a794ecca51b17efc2207765a5654efe049b595d7539a0d497cf9a816006032677abad39bf0d58652a493e9af4b5fe2da97dbdc58a9ed3d35547addc500b5a720c523b3cd47b0b0c24ec0eafce79a44384d8cf066cff4eae7197e4c630005cfba09d9a3a60832d8d71c7fa1ffd2e2a0ffdb55c29399e09b357d1716c500646e77b2c8e051ae1a179501f5a0ea1d9125089dd1bd4c7e02a8fb4d3c0355003da451831aa40f7bff796f912bf95b766a66d9077e9b869ad1b87aa394ce4c00ae90c2ab20791dfd85d4c7ba973ca550bfbfd597127cb6a7915540809519b50027ba81262dc611a32db252bc4196781956c8443a53fa80027ce1c876abf75b00d8043559732d06470f4b8a7ad4135d82410ebc327dd8e92071b87b43447560007ff0819c7c9aefa84096ff593f21b83f894158ebf0fdf0bced4b20a248caee00ad93bd1c49c621cbd561022f346865e4e9ec56956a2ee7940df6cff8e5c8780038c5a700cfc9fda87132cb99bf85f4c580cac7744b3e4d523f651edd5fae64002cd1542dfdd15333a8e1af3d11d918f1ef6baec99b1c64fe3b583cdfe7e3c3008fb735e344c75999ab4ae8a669818c09df1cb858f83e2ca070645dc885636700f63a5227d32e7866a951f75798b4a634f25baf83be2d6056b040f95b7a815400e60539de2ed07802e24fa6f4654154fcafe3aade4e222bdcd0b3f76406cb5800b7e84c33253697cbf1d58a0979b3db8b82d686455c4a44fd6844a0b1f7453800393bd217e812911c1f3b52e619d23a4c8ab15997e275cbe0e3bff3c4a95c750076208501e2b11f9b0be1098138c21925c35ac4345b90c26614169b8f6a629200ebd883acfd5fd3c241da7cb4be1de3e86e2fdf70b4c4e7dd0e05c44b9edb93002f7c9d2cb232cd6240e47020f0e0b418873fb52c5521e33cb04a8e09bd6fe2003c8c38e3447019557b02f6ff9ead33d5844e29a73c91e98a6f8938a8cd13640078439dfb9d3fb0618999969f583ac2d5d160c5885b5a16fee536aa4657ff9100e10b7bdeb39bb1f8ee41c97b92369fa8efff1440d32e796f92781596be60dd00e00fcaebb9a421c345eac75093907776757432fcfa2c8dc3bd115d4491b8d000f257b23f58041d7d6fd64d616c55916805b9a7795c7ed0d28ddb609395dc2100b8826797b0ba5604cee59189f72bdcc4ba94490682f8ea11843dc32aacdf24008cd8d0b2eddd83def4774f0f09385ec91172dc1526f6e4f609f12ea42ff53e002dc08547c2b90e481639476e237e78e67545ccc896940c3274387d57dcab53007851ecbc24b067ded869415c24f6a5f18b73b3a99ece21bf9fbb476e50fce5003180bafa6e9ab72abf9af928da964fb7a4745274fd7d156ff88dfc479377e000d058cc585c9562e472fcaec5bd22a5e5105df9dc155a350d9156837c0ffd3f0083020073e7f5dff8dbcb23cdee9a41b74968d7af6d09863b7651ab65009b150029f676d92ff87a066969588d3c47f0f928922625855d706975dbff12fe30c90065e21bda89d23817c1306badbec392cc5312b87ddda0415b40cf266e43e1da009412c439f6ba476621665825432152ffdcbd6cfaedd9e4cf5cc627eba000a100d6e0dd0d850999fc1fdf146f38b076c6e90760b8b76a26252b297516208f09001350b7df330ea90864ab8402ef262cdf1d3bd7e48ff9cf5b342aade285959d005abeb23348b57814005fd555bcefc46e89846c5b5187b0660dfb54352ecada0012c1426d079a7af9e684cde23785d488239eebd3d1ddbec73ca0bde877326a00eb00748a39520110520af77961be4ee2cd9517ebaaaff371b22b36cbd82b130023c1015b2b70875f5101a71d0cd832d409264bd88a0f507c6645b89c4ea91a0011f2025f834c5a0623441b7b71bc3f34b056321b1cada53f60146db7a0865b00ac188de1a8e1d60f9617f8501a3dc2c55fea2417aa543f31d7afedc35e94320093b5d38c873b45cbe132877f1f2e0d6f3303faa9ac21b741ad5e6f140541ff008db37e3e19c09180bbfe627b9eab051c130029ba8be671351f2d7bd9b47f5a002f80222a61c7428fbdcedbc1c778e03b1acae1a8d229c79ae9f2a32dff525800f1c0d47ddbb6765202c346e9d3b0891ba2759083381892fe9c799c01afb585000a4ceeb11a3d20b380187b64eb9f9e7cb440ef4c0752ec7018c88fed1954f00060e6a71b86f89d755ae9eb2a6f99a3fab422a80b4abab3fdfcd322ba692f7d00330d6e47380c4199e73bacf47b80d76001b6331f055f110c12f38149c92f5c00fd03734cb4aa224b8ab7086af3b6d36bfe51b33e4d860209c2eb3717d9dada006eba9473d9e2d128d702120b206ab4068e2afb0caeba2ed5e443f87ab94eee00c30862ad5acff8d409e1ee84cc68f9f7d2ae761f512560302a3b99215a43d3008dc88f78df0c2ba12f4b4307d739d3796ef6d74c65b34a39c8808a54607738000cdfb2d6fb1756164ce0062e0fa46510a8060ef85284897876a008d70976cd006983a3bd39e765d1db499ae069b0b0a3cb639ee443c5567b01a1258726976a0036d15634ab925c4f48dfbca718cb929d04a508a8c38de42e4d7f51f1a0c6ba00c05d59aaa2a464c9dee25ba195473e2d0bf9b2c79b0613d4ce932074798c39001bd85c3b021974ac90cce937332829c2acdf50a51c1de0d8784330f0b9b0d70071a4168fbab09906201b40052902ef501d7053202b91999d9c3e6825ca6faa00f6e01dd15738701a06111594d6a8a8fd71d1bc193133243aa1aaedd5e7025500fe6147d44e8acce61cb3a602fcc33c9024ec3646936522093a2584fe153e3b00bbf9806719095a0aaf5a2c030d90fbf22a113c0b9604c0b8092c916a5c35a40036124855ea9880a14d9f4b0af0acdcad66284638d39436861455d001c79286005e719bdfe47bbec9d404c724552803294fb1947fb93b7222e686965591a807002942785f7fe3208f170e3298dc16b82de00b698222de3d673016326d80428300ccd1998090e37cbbf5139e7b6dae14696fd87cecc47bc44c2563d84b028bff002727642871e43f6d433b05abc81a145558dd425bb8f912da3af848092e006200d232575673e585d90733db4e0c31c6c9cb2ef9d8fe1e980014cb59e0dba98e0028f01ce9d6bd7dd29b9da1df9c9b483707730be1fbe532b2a553e77cefcebc00319ed59acba96538736965f512785a9d65843f1f6cfaead56105cf49732d3900c8ccc5b9b044d02a6c7f7abd1edf4335a75a032ef9fd2ce8bff0e653c2fcdb007ff56d0fcbbebb13602253b6f2751938ba706c89f75e2666b1ada2aba6e731006cc67b1a587953f6c1c5eb448c65153025503b59713683fb63a330055265e7006c9c6c4bd81db9414e06d8f01f9a54eb524baa33d3b357685f119d0b9e5de8002517a2cad86ee8651729999c28d85da56b0a2cd320c42892d53bdbdeb277bf0034f091db46db2a78bf238b0bf0e11efeeff89be2cd81a6fa990f955e99351e00b96b58797bed1ee3bee37721d482cbb6024c69e1ead9ca4864447cc4eb6e02001a317ad5b7b53d181108be3500f09ac214f4a739e1adb315d311d2d065130e00e199b98b03a38aaf9c0dfca981d323a92e2a7763ad964d24317927d8f5408200a72855dcc0835dfff7c8a8ecc3c04e65ada0c103e0c66d7255b19c14fff2140041f36f54190fa20e14e8f28f836271c4c2e48585f46f80c41c8df6f9793c4f00351e28a44284053e678a23428fca61d9f3c1bc79dfcab82c269aea5028555700926ce6e407f3d0cf612348dc3e8a8514896ad14ca7b8426a92500cce77c7a40090f9a11770fb90584e2b0ca0cae5692c5ab3b0354525776133664c3e67bea6008046817e4bfda8ec6ad2dc87ad6d410c7cfe7296fed3fd3962e035924301cd0019c678653086ce470601abff531019122efa858b22187235353482570d12970060824678fd229b72c33098a7990b5c81e5d87666e5edd6185887123e4574b600ceda205fd5045bbec8b739112cbe1fe6e39845506fcb0d15e1c0d3d78be72300b03dc5515fcbc87c5d7f9bf4a2a8d6f7dd3f782d7ccc0054676337954120ce00bd06c527a189aa3317fe5671fcdade393033d94ff797be71ab5f8c9b82192900d0fd9ec2263c8b4b6345a4c18724f6fb2d8dab9f7131e960db2ba509bcb01500bbe077f38313d8f020e8321fbd5777c8730faf8185e8cfd05865742a8166d500a74703b6cf023a4c077b38b818716025656d1b3281e05e6685f8e58d2a0a2a003f81ce2ba7bbbb422d5c5f5b3d2fbfa2f0a4ff66dadfc67db6c0f77eaadccf00ddbf75777efef2aea04ffd64266b6ee0aead86070114d10b3b166209dc333d004c24be1869c166a6e79b5f2d63a1a3efd381cedc11f5b2e3686639044e4376000b10f557fce9521a5a2a85aca72349c3c07b745e19a2f8d31c505fcbede382008255d30a625a1e83cdda08376008832da615ec2f6ce6391aea6cfd4669e86c008798ce08dd7bd12b3d13c14a12de6d7df9a353ebb406c04f0ad8b6a37ff5cf00e2b88d405b1e1024ffb53256a8566377b92753114aa64641e4a3f7cb1454ca001202910c7ca1b286284f6d934e93b077ddf11f4ce0fdefa7cf9a24a19bd5db000de66bcb448781b98de86cae2f2b0a81be3ae607bbee410f8ec9a3513aa20f00a59007f6ef2f2a04bdca9219ffc326ab0a575d236873b3ccf8ed24543376ab0093da94e7b39232cb0e9ff74026b4beacf29370e98d41df395070bcafb3a63f00da56f1ec1044a97e8c2f2b02b4847d36f79c1e4c5c020d1f24c3b7c04a5205000e7bf5823d6994f9badc230ee73d8e78327f651bd6c4e7a7846405dda6c1e0002ad755674f3987880efe6f9962e74d02841f845fad1866283eeff58be9467600e93e3012165f1a4bb69a9f8d378b22db98d0ad430a820c6810a1d578add6e400fcee631b2fe1a38353de9dbda03f8d77f592b60d1bd6bf8eaf1e713a7e38a60041811267fd17c9d6b5a43d9c1e0d9368953bbfdae39e0e6a5d785a5fa2e82700df22cbc733af9edf4e65ba8626976a39b0a2cb7e66ff8817a06c74b435cbbd005db63a502104bfdd239d53b2e7237ab08108c94e3887951f8fe043ab0479c1008aa1cd46f939b69479c31a03a0404adf7ec5c9abf7be4d7874b85e719c27ad00671f1c95442d79d745b9a5b1d3c3a2d2f328eda2c52d738ebc54b211fa5ed500c0f10a1c6fd45497f368eec981126c648322f15a44ecc7de5bc089d98a5b6d00af01bc3fbfe57bf78657a459fc90d01a3165d6529d7ceaeec13bb9f94ffd44002d4b61f3903ad3ae3a9736b012ea906196a44e165dfa543501800976ed4b8e001defd6737a47e682eb4afcc28aa064ce8440ce7ad4fe0f0f3f5441fdb91595002be3ae7c854fa2adfc4790ad389a1f72653ac4a8bdbdcfb0bacdf4cfa008ed00331e6d8f6871a32ccb8ada7cef0cfffe8794957426de7f969abe4b1319937900828a93f571dbea9bc7eb9d891ec856d0fe138f1300ff3db6a9a7ccd4fcc2a400f73f6ef1b2579a71402b082fda7399e3fe93aa2bfbd83f1e74173a17e2bfd7001c5a196e476e10afceb5ce46e05f9341e89054a6e9aa55345473b9286da41c00da479d6989dd0e70aa2a4b9aa8d32f1286d1d378f94ff26c6d634b6a5ac77f00082c7d6d88ce8e2bcb4c5c96e97896cc05b2026ae2effc44edbfaded0b981e002f78745c0f6ef10d2ca59867d64683f7ffea9c937bd1b10a3cb7482c360bad008bf29aceac280530e82dab4ce947e41021601874121aa0e47140405eeb4e46005c57956ab1474f44bffd85a4d64f2e71bc4ae2063dde5d47f4ccba5be80e880005ccdbdd7e8f9d988c5728f2a2592866ac2410be8b934a0f77dad03edf11ab006fec00b8b43528e40eb3e4d5285d255ea3c5ac9c1496ad378b751ee7a278880019c6e0da3e53977fe03b50b0d7b3ff4ef1a2271ccff68f628cc3bfc0fdc4c00063325ecb022b0edd73df29dd8e100f4acb9ae67223efaaa4f1a3f4b9bc318f0036ba22f6b3feb41d5430335c24cf27a9ef4c5eef450f604cfad9fb9c2f504100fb2bd282165c71e9d70f05ca1eb6435a0c2c906e825416d2c5a3514ecdddbe008927612907132489894924f4e597f9d8e89dd96773624eec8ca1e1e9a445e900be6f066c7895415375848e69ae4ddd2ac39bc852ba4f7ee097352e5224df8b00f85a0e11b7af7986a415fedbde2b901826f67eab7f8c8ea951c8138c9446590029b3f5565efeb135934da554cfdfbb508552f1b1806aac262f6217a601041e0041199a6877ce2c31f237870dd1cda014bd0c838fc912c0b381b04a7ba60ba500f8d944373501892a3888cbfcde4b6dac2ea68b943d951bf8c0c7536b40e4a7006305691aa80a27f90889624cc0c5069091c1a203bc38f9ac5806135bdcdd6500b50665e5822fa7e0e37b21ff93ba9beab925ba4cca826fcb8b850743d376920042b1cd6cddda206ffc47fa94c8e3c217860fcdc4edd3db4f8b4b4daa4957fe004e5b1d6cb9fd3c8847a98bfe38f182c787a7bfe64551d80b8c9e2012efe05b0023c22ccc02d6361ce6ca2d9658d9a7299c566ed24515ddc51f4d3d5335f9e200150dcbb75b1fb42d5b2f56913dc3313b1aaa1e42b248f794e1949a1d612e520061e9dd3450fb1a164eceefc268ec4e2d51baae25144df843f6e3d4f6f3ae5b00c09673b63f6ad7bef6ff5ffdeee77b0fe99e7e997d43da7d52cc8566354e22009562b2789c7837d4a74a26110391009c8f944a1b98021582401e22d71b8e240032135a43b3d4da57cd4459a5882d4500cd065674ba0c888b0361b0c44fde160032ed5058766d9618eae86be79721d770f07704cdb1a3200e37ddc68d86565a00e971b48dae67b2aa45e01076f9d0fdab33bea54b88a07a02f74418c62d266000059a424b251e93e2f96e67806fe5854beeb186cea19b204f10d2ca72b61dc7000fb94aab739310e050d08d13ecf8d938e70e3e7fb8bf7976e91faf3d1c142500fb1feab1003375a2cbe362136956459c304e201c81a63628d5bdbd3d4c0c0000492e5741eabb3f9b2806c6025e9a9fe06551b7d0f59c13ef16ef06356d341000e7defa80bfc80c014bf58bf0e44d22c3fef1e808bac39619caee8d675020ec00a42985cf739ced161c3651fa67483d533514794a3953e4cf7a2f273ac3b95b00980155adaf0b3d08ac749c2981dacadc8d1b899da116c2ea4f85fde359786800db685f59dae0481b398e2db640283da6188b2bd284c8c07100e7ed9f07f74300544b0940a418e2b4008c4e6dd9ca1681f7a02f4624f6a6751dbb94ef1274f70035c36ff437c7bc2bec862b63e992b579b2fd5e9ca40d054ea9eb93adc222f000c57ccb7478da83ea95b32a05cfd8b88f5342059a913b151c0c3ed9cc8b671b00231c6ea8f2a16418586d7ce86d1599b4789d50d56199d73c3567ce99471513004c44197a73f79381b4a778e36a37fa98f9c194007d1f4a1d539fc0491f0d3e00218fa9e8b1e432135806a53a4576d5053a861b6046ae8e8b97cbc92738ff9b009877b3f169745f047223b29e6deac912ad0fc776c71cb1101f01c20cb80bd000d3150bd8809ab2572dfa4d3b04cd90b3c2f4e0cc69c778f5df979c6cd802300081220f94d1d620ff5d76ba133f2c5df9318d85a28e00b6915574aa83a7ec8400ff539cc97af140635200700c931cf38c9417e59b80977365eed4065f238952000796b647eb7ddbe687bbf8d1edb04fe3d5c1acd50c2ad3088f09b450bb529800e3655474739718722e34b5edf1a3eccae41d62559201a60fadabdad486cc04000dc99ae8541bc0846f5de8e1132c326d071cdaf5591e66b3908902dfa0eae400bb54015b36529ba39db5f81e52008fb238c3ecb5158f34a819d1670ff68555006480b044c88c731c7a76b46e1346b72f855b21f8327d194c42a4bc1ad7a39900a937957dd3dbb00bc1c8ce618a9f65abae05fdeb8816f2721ebf069b99dc8600051669038e127372264f7e1d14e38c44b46a482750e6ebfe049ed6c6633684006dd92493f3becf0c08f1dc6d0503567d0fd85b6d12bab86af720a2872c05cf00bd34016c0901cf4457189e47fa24703eb75063903fa1034e99547e53eb32520011635b68526a30ada2ef32561506d1c17ad58fcdfcda04c6d6d92135e7a0f50004946d91086df06cc834fecc5334357ef88ecdc33c33aa51a99afab3dfc99a00261e2262ff99bebef81f5966fae1a61f2f263da4cad4139b96936eb6805ed1009637fc5f523977e5186b4b5011a1dd9a0fca3f904543585839def6ddf2a589009c9f4000458f3c38e4e5de1f25edecbbf16395e134622a6633291b70539e3500f8facc1947e8c791fc12fe7b512660678e9610191bab9ac28fbe7b03ae46ac009c6e8b2b6e97614beaec7fa2edb631fd54b7c1008e13ddd35d75928b1f316a001dab12aeebe310e439d735de83e3695f49f4619e7cb63bec74491a80606aa000291b4d572e60e15cdb4a6d9a9276cd55424366fea4f74e431b8807bcc3e08300babdd2ebfa51e2315d59c59a3dd27501f7879c030ac94bc1c78499ae65082f00da3d14e624b78ec6229630084092722d0caf3eb46eced7fb5b06564cebd372000b2d5c8d7ffc98b9788f9f15f126216efa2fd8b89b7c83209cef63dc304d2c00a3de8c49fa2a8970a3ba29fe2466c8fc27fcc4120e01116057b541f23054fa00163fce8b4d2a574968858b3a325535106a4ee4ad18b6b9e9d1834c820400a10026dccc20ea2cd209d0021d245999eaf7bf29dad6bba44a2b2fcc1d2b6099610068fb2bc9a07090602e86e40a1b974354f6719d5630596e58fba44121b6cd2e00535c907d01f5c3693004c3434dc2b1cfc36e4d6888ae36d1378fe2262d9aae00d51c59d37ce8680fd9c054bf90455ef9777ef6da8272c1249548ea858ad49c00a269b911a5bbb5e2ceb547468c8e3414f3398dfaf097f51dca9c1ea2149e78007f4b47382555b1298b634c7e6cbb29fa0d4a0f1921be8f87a6c4fcce3b089e00485e6c8eaf679fc2d66bfc17e6fdabe5b98e819b0ffc2ca04870c7630ba65000de8747a58109d94f144b7dddda736d8f43b92007b9b23c4c4de3d22045ba7b00e09fc6669be1a7f20939f466ef0bbb4a2a4ba9228640c58072765f15fef2e4000d9799534ff72ab57d654d0561e81fb39fed6d68ce547d5cfbe629e229451900bdb61752402eb87694b0f4d434e802bcb148be0960bff4a5c9a0568e6d6bee00518090d9685b54307e31b03d46ea76e2a271129768d827df6ecc719822a5750013d07b293cea07ff7dd85451900b06f9ef75dbf2ca37b1609dd705b6e17cf30022453df34934509a94dab058aaea60f37ad73006cd8abea6705156ce711b5800f220f712d42da63daa442f2faeb3ed75d03300db15d5500da04bb0f40114fd00ea670974191f0427765fa2b39d24eba7e25aa6b5a4eb9760a6f84d016f0492001be2b9b6291948d09ab8adebf3524aef6cabb464d45b12750daf70c1e9aa7300e38c004dcce0d91b3c55e8040f093c16dc071b65a32b474eb811423370290300cd69ad3049d20076911eef02cdf29b4aa8cc506f22c5cc1d7a758307e6d7d10093bea3a4c60d415193b30e89321312c62ab63c5f4d958e9bc282ae98ff6fb000ce7fa5a0eddda6d8d18d2509bcf9bdc1963f9bede524d59cd6376620f9f56b00521b5e2efd1b43c151ec90183c3ab2fbc3e225bee715552b6faa6033f70bcb00fb6308d38785faf2a80f6ace0855d261ae0cb360bc5939efbb305ffdd2c62d00275709a514ea4125ca81e28aaf85ea592b86a8f0784aeed366e8f0a299acf500d7b24388b2f063e21d7b04cf226a59488b1213f34d2ab05399fc1c05e3589d00302496a43dc2ae93d095e659fa743e17600bd6dae5aa1b4cd4c52f44fdc3f600aeba2fd52e8dc8ea720fd0362605ab8423540efdc04a98c3cef02bca760bf600d0b57aa1e5199acdde3c39fd6749729a59a453df6750c4ba89508e36faaa33000cf54937ecb441f34ef7dd1efb2e8412009a5258027732cec32529af91079d00c82b92260e70cbf4038b3d57181accdc802e2b1de0089bcf5bd7a8ea982dc800bfa5c18defc45e19c4bc1777bb75ba79f25d32463d74cc4a4cb22bb09b3ddc00eb59a4c7f1521e6e7282f828772053041d7522df21fb42795a041169b33b2000c610e7ad1cd21c47308cb83a5da99e7fcf175025851aae3c02bc7feccce0ae00a49625014b738dcffceed7ef52ec85ed2aa408823340095c2dc35bfc3c22e0003599e6ca421eedcbaa04cdb1ed0ab49dc1ede38fa58d19d92a8175aec74a5200253ac705e65ebd7344c434fd839530dd3395eb1a26efcafc721bfdc2565dd900b014bb6df3d0927661309a78985d1f3c8271ff3ddf78392a269c83ccab68fd00e0cb790fd742f94891d78120600dbc77ec290a80795a5324d8a70d165dd19900c5e5f81c9dcda763bc89df9a364db36538f61dcfd9edffc72239c286ecfaf50099a888aac10aa34bad4f26439bdffee1223d6e8de534cde399a07b77235982003302c232653fabef245fa839ebc66303e7dcbff605d51375b8d6bf87ef0ff4009637d0d541e96eda98fed92bc67114fc5f21151c194662a31e44a07cd1c355009713aceedf474028fe799cd3aa98635264d66328ee0cd041819d4cc2c98bee00a187c430f96a6ab5bb47770b7959438d513cafb1db32806b45f463e4eb317900988692a371fec2e3cee04f4a4642b5591b293f7447cf466968acc71669b76200e2a5f44077e77594a7f1f1f68353f1898321771894080b05b80c9eff8d0ca200ff29a2208b4d1811acd515bf4ee9c829970d6a227124eb5dc48dca7c6ad02a000774ad5f5b01007327cc1ff8b3b959ba298a09136a881a697da34ea08daaf500f6fc6e6056b749f94e2bb61ecaebcad6cf6aea2db2cebed20f45b310ab8cea0014db6cb2604d3571569afc5616b58ca04d55706ef368ef0ad608c84ebe8b0400839d4f0cdc5b5828f41237c5c24a6c045b81a7f1805c8c3c5b6830ba3d82c400579e70bfddb7fac58817d53c0bf02f42844ea7ceceed5155455ccbfbced11d00b22fa202fdd2c3f9641f704e305dc93675f6f1426805a6da21b3c33667e6a800a0259f4ae6507fb83316e1c23ed4781af82872d63d8c6771eec0887522261c001cf6587c86804de5002b950dd850d0738ad3240b56f4881a5de85937d6f28400b7b96a9ffe28e52e94ac654b0a85c3fc45f04a85b9c106f8a59525a8b8faec00424fd508233c917dae99d9377f96d82b75b7c5775355f1ace8a92a062641c4003984f8b4b8e3286edf1cd9c844807b808a9d3cac327931a9fc2cb75dbef7fc007208b30a771c41fec59850b3c8a24ad1427a4cbc352d39ad04b1d5e3a1eae400e793378a5ae8fb78fee511c6f459add843233b63c10622d0a90ed5b8d0d32000e1c04f2c22b4e15b91643c33fd0cd1b5a6b45f85d42bac9cfbf73d7f2f11a600bbc70fd7c90ffa0f6d1dd5bd1fb7baa86f00dcdf466a019070c77f5ccbff96003da086a71dd0a62559e65704034b94069830811ca2bb4022d42de353f63f2c00bb2875f27d05c14edf7076aeaf8ae7baa0e3373d035af24324f6f6c1b802ee00c6173d2672e932e72a8224626d8c89d86a97e715db500f2d9d680930a55e71002ed680373dc04590237758f5a31784988690b08c17dfed9c0d756aa1d233a300c8f74fdfd1cfce427c5fb02747b481ccb4a3ac34c2cd2c304ade9f4e846e2200054b76411004b8997e301acfbc89787daf81d80c6a6962033ea6f6c1e747290019eed6fe55fe94a4e607ccb31c884713033b821ea13167cfcdde7f721c419d006e514aa67b5c1232e03f3f1a188b0805227b3dc84841299dd66bd7ccab16c90015dbb65a721eb4cde17b4e61e7447d6eb2a720e3a3d59c45336f09d71c9d2b006f614f433d2e1cc9a325e5e33f525102bc80cee2bd7ccfd9a5e5041e68dd38005aa26d15ad4d4f8b69d47463f36cd3325f846b4cc7c006e39fc5c021e4d46c00c853e13ccc4c2c0c2e99c6d75561acd5e373ef64c7ebde909edf6ddb54c10c00ee2783063cd494e0fd1030aaaf450a1a8e69f2091b793a5c0c6638d185adc0001ee5214378ec5aea4dde216dcbf5008542a2e40f4c05b4dac4f5928a09d8d80081f6540f943f4b0363260dc986acb016128a7b6a56bfa5b631145ece97ad5100eeb283c4a3ea73b41587e00a4ac43af764795a6e56011108d734ad256b58c70047280ce36d4280909c3d660a1ff729ef6e242b50693fb9ac93ee5e7c914ff100ca55d70cbc3c3d5898818294e4f91290e727c8cc14899cb3dc6fc8cae8e52e007d81c18ba1bf9acb7e1cd88a67c030ab237aab9e0adab89ce299872ea2abad0099b8097fb684f8b31ac650eadf3d41524a085daf9dc7a75a57d30625376ea900d05fefc9ac224985731c697b986984956d7c6f3d10c19efd66468b7cf6a6ff00943d692587cd53ed60c455612c3d286c920f5089966eec876be481e0ed5f3000bb56452dcc3abeea0505ae17fbfc4b7ad8c689cc2eb7464aa422e6a5d29bac0099403692c5852600fe2fa0807461111a87d17f88de1d8c6883fbfb132cc64a004c3af403ff9c0f7cd5aef933c4fb23ed5081f4bf1b20990555c2e0fab6319b003ac6e7f93e23397233d063b9ce1c3b15953646959f53dabb17aea2435d204600b7df7be2297a99ce8430ca242b153180fc9b12be3c9b8235fe5b5162cc665f00d2afce08302a381dac6af2b262807f46f30bfa2326ec6658cacaa3f2c833af00755369b9ba4349a8bd42b132620f7d6dfd2b430537fa79b38fedc9a3b8df1c00ad5c072a46c52951ade77e4a5241e5ddb8c3d2d3d990af3561bf303716d171007089d4c95e2deef8519fdc03a8b8f72e034e8e0a16a10498c628282e1b618700275f88355982a44303168fd7536a6e27654eabdb6848d9ab91205d56b2edfe002f406fbcf575a70739ba4c9202c792ad2f88ca4a88ebb09493f58d06c964a2003876af82c89d3caab84f07abbe9f56e8aaf3a1a393a60eb456f79a387a25c1009e12c530798c755013a073adb2ed0dd144ec66e8293cf6626af81fc520d3d20047c052281c452784b5c891a4a569495841e3a297f22223e0d7aa4e8f4d90d100642a50b341cb63e72883acfcbabcebf79c0a965752e090269058e11c776b9d00d9fe3a4f9733111956bd1c53e397ec76f9578729beaba5046a18aba235b11300842d531a8e809c05cdf3d7a33ec0b5738627103789218b15526e012efbe24c00edc48d8b8e464cf88edd8e3bf3bef55ad25bafa7d76fbeb222cdf2738e7e0700a40b7e0b318463cf491707014c232b2be24bcf7a721db15077102db2c5a2f50085c57cbb8722117d545133189572fe8c71cd6df8ee34b553501ed5945cbb7a008a70687aad09c4c1f2e4aee315fa1de1d37abe2fd47a3f006f7cf2860a6b9c00882e4c4fbb7ee7f987462cbb694591c764802778330696c26c5d07789b9120007d604c7a8c6c3654f1faca9163d03c4d73d08fede7a24be3244a8f35571b96005bd8d4cd11c8b47fa59384a79a6f7398aed6d772a9f08c370021689a6dbcde006b0a38a387f290088f3b140e3c8a850fb5453393fc3c89bd7e944d79254d29001aa76379731b93c9e159f6be337741af606f00c9fb723c3d70761f6ea18151000d90849e323d1545d1472429fb3b905354e98824966cc44369c3fb3af34565007a8389ee37ff79082a92bbd2722cc792ff3c70227c1429d1df733e7c834f3b00f83c325ac760c52ebfe4ee638ae6cb77f45da610b9d39043b307f2c3907a7f00ad182bc8c17c4e3a11d19faa779b547d2480ff846522e33f0f0c49d9d08974005b82fe04789b847814c210021c4b8cc4f7b1f169a9766f07fabbfb08673dad0033d0fe7c5ea41187545676e5f6ddb46cd2178baaab4e62a336d6e787b87b3000e973953cd3c8ffc9f51828941cbca649de364b71428704f68420a862909eca00fe54d5d2257c12b31e0b772590a2902d468cb5ec85fd26784a297f00ef49f700a5cb8fac880d254d21b83ebb10a4852a1e10dc4dd8991eab9c621415d6962a002da59d1bcccce5e7dfcfe6cc3296bb6371f0a1129ea7697825df54acc2c85600c47521950742b2df20e82e49bbc6d82876911343652f997048c1cf0bd14628007a6d2540a51198cfcef1e318200509d671799a00766025bc30a26980c083da00174ef04177353ae29a1522c9a5b3ff43fb082ac2e4cc8c53d5ceb34aaf71ba00db897beccf13683f23070b932033196a509b8ee62c11bddd5a67acd495e70a00bb1c9f8c0f9d041341564ec8ae4aaeb548e5d96298818b028a71cb29374b7b00d95d8c86313a14dd3dbfb74e246adfef78edbbc1383a86e1ba906c406189730050491a5b1befb0e3820f7287b2061172fd51804787657003f2618e9c7158300065a4f0f8c9d8bd974eee5c3dba06caabf71c775bf5f1dec81127e6f8102dc40073d37b824403de02515d147f398901d3531db682e9c489c6ab3519bd266db7004c2e8f706605a246604dd298c92c5d62cdd6eb605bfcfebb292c5dccca8eb400fbbc876c40af0f4d6b69839167150b9e531dbfe68d88e091c1e717deb9e75700c8ec6012e5b307f2df4baaec48a9811ee0ce8237039a4ecd7792bfe304b52e000c208f8c81c4bd1738ac2fa5ad79d9cc5fad37cd2c05792bc619802f3abb050085a571a94ce4894e276100327ffce5effca01584bfcf0162eff03ab904b1e600d1a03111750e0977b61f860d56d2a1801e67e46e19ccf31cb061d5e56ae68d002237ecf6161cbbffad4c845798216098043d26d6afe91c7d1bce96316f4fc800caa7c0db7b8362181f280ec0fa0014f5610473cd7d339d3b2a11b978fde9bb0072ea9fb71d442c17a4dd105d29528081278775eb86dfa54d895864c0d16c74002bf746b32e349ced7d1bb389514ee03dc13eaeb77ec72652ac48caee96c75700f5aeaafb8784e32d3975a1582a2a4b316022465aff2d3a8d365a2a8379c6530080dc6d6c1cb6b8f0dbdb5b92fa67a3febd60de6dfb25d0cf75800675ce715e007b26c738847978ebda93a76b18f1c1679e85647231c8a99b92b125ec61831000f1750389e001dd45a4b04604ebed0927f661e5179a6a27f8bda35191e29b3400eb9003377f67de461014ca2a79df6cdf577d2e64d0006459216ed4cfbdebbb000f6ddd134d26ce05420bef6ae55319ff414049c282d70e9c2febd8a1aa425400c248bc7d13396f4dd3c2b217eb0a890bbbb755962c972861f0259068d6cbe200bcc55c5ac66f080efed3eede871cc43c8657b8eb81082902478bb3de29fcec0078711be086879209c0069bed1ad47ed96a3094476d3e197ace028e54c29bf90087b5f9632593c411b59e73991b8d164835508eb45b62dcb82bd12ac5c828f50070aca9d000878704d40047dbef97daa3ff8b16d221a940ff3e338425c05b8c00ff4f46401813cf6bf87838a7657db80e9070f64763861ef515acc2ce46b4e200a224d3ab95e0a05615523adbe06a887b13516f87cd6ed62bae35f92162a8cf007b133f49fae570608fd4f40cb4c729c9ee61440b7ccf52edc412b3882733d600021017700eb53ba31fdc250f72d213541e94f41f256670de13da5a75767b1100b38563c108cfd1ea8862bd4b35b5f770eefb290c75f9c6051156b5fa7c17d60040799d25981f9f642c6dfa3cf7717ef6d70ac23fc99996125770fd80da704e004590c90b174b237f095fa89dc9da1ceef4e45f79391394d25ea81ae3becb07004dc02fb48a8f0ba7e38f8fa9b9e7c2c93700b7ae1d424d2c1de43d97e95ee700f1f8a9ac4e78db58a0b9e2e10b21fb5c462803a21ba3a147b0463f47dae12a007cebdebf220994e86de03287a410b8491fff899aad1de33db3fa5c81576bb600fdaef9026560a2ee651af96d130dee9a367f936245a372822a6af972ac9c79006fd5207228c44621a4adba861d67a2ad68a6ef1efb98676ca15ce21230eec200a43980e947cbb18ec83f435db0fe8feb2e62d51a000faf399f1da7e3fa8e7d00a597bcfd96fdc52b24d29f67d21952b229b5133e7374be29bfb42bd793c6d000b7d8a4f411102810ee110f55314debb1982567ce2d817dc7c32c093923d4db00d0de93475879301c29f5d9d1fc74f011ae342d31b5648fadb338198a55bb9800d5358ff22f9be996e6d3bc48a553d829d578246dd809305b45d7dabf1d7b09008c46d1083385d1726bfcdbd3bf9921ebee2dfac87e5b642350689a6a4bf3c0006a28d2501d1a58c76fc4d6dd8a28bad56859cac0481ea248ba440df419230a000bf730432ae8895ebdc521c491d83f22ca6389eef7d298ce1c1438bdff990c00be1cdf87a3b4e09eb96d1939296a044da7abe6f3304bef25d6633f04a8046e00ca5d32ccaf571be350054578a1e6239f82fd08da59f32b25dbe28d45a54f8200cd7e3a0753cbfba240742df4daa07835a893a0f38749e2c8d83ca23ddf706f00cf06c573f00e74913235a077f7a300bd4241b8a9a9a41187a20e1c194e32ea00417545f4bab79f3fc16008a003eab63de427149a783c78850c2e1a3a53774e008fbdd9d95b5f51603ad4b9554d4d51533f0b5ee68959c764a08bbc496047c500a5ea3132d5479b3482bc6b50b500e6207b827d4176bf3281a58c4b8964f41a00d9a32cd2d8daa7b92e5ee045a03aa4b3d80850a665177b6bba31d032d2ea9d00de83831819958559d1bbc2f0fa1067754dbc3dd9d5c0ff7033ea6a951aab67006b82d5f20a6602fc587949b64729246b8a643f356fe7321c2170b5c106180d005713c73c3f13dfb6a4b95cf74760321d784ec9cd4a3f4378777a1c29a61ecc00e6b2a5281b4b4c4006ed39bcd7c9835f409a919329f7e12a1fe5acc7e143c60092223f4da10fcf4b3607f6fb348cc1e3d77ee739142fafc3535d40bcc8e6cb001d9b9ca26a2b4a47c380bb8bb37aa830a44f46e0de279343bb819332d0bed40014d5bb9b42ac0be798e00392b63b1b39e469b6d614756fce91bc64beb5244500973b68df711c521f04c9ab1366ccb7e71efa974469f029b82bdfb8f32a3acd001bb430d8e0476605e18f175edf783ce6a7756799f2758c62c984b5f0e984a7008e09996a6d10ff1ac09e9655004f4d7a70fd410d83312ab05b49ae36c004ba00507635aac4d7b891d6097c792188c6a879bf2b8e1b176ef27046aab420866500da1653825f7b2a8f83170c9a853b8d8b8629b2af30b3ddc37642c27b96164800e8b3f84608a436a7c7b055b0df4563190a05e4c7d8a8c705d3c52019e63fae00202ebbefdb8b2bd9583ea246b782063cd9ea112c84a8153c2d790fedd61bd1001cd2cce30aa284112e3a6a844bf6fbd3a3cb2f140f5693bc42b20420a741e80018d5b9d149b8a5a35086ca5d2cc4983989f5c8036f7c86b74a309369fb82ee001cf8c341f916b429d6101d27080b3acfff14ca77f5453d3c58aab23b12dd4900f9b9c79de2a2ccdf97b7af95f015058ea5d407cb2053972d8d04dca3d898620074991a56cce1cd127c1d50caafc359b20eb7932d670ec6b7037f52fb31deda00a54a123c4525c350b6e2df0ed623ca80ce33fd449787f8868a20f7dbb3e722001f3dc8d432f2c587452e77c6eac8a526dbba22109c5576cd275833ef57642600f2e8cf048cb97c56402ff774ce800e8b2e2338301870839ad350614327dc060055b037de545af424579eaf39bc9e58566326d4242866f984b3b048b3540809006bddbfd3c865130ebcf60d9e90ceae0417a6e7fb0e0dd3ed870cba1a8c05b6003e869693d8b16b33387672e4d14d6d9c180c5f088c2616686be7f84de7f2e300850e12f7b736b2e3e56b177d2a8e70bcf22ff3f0658a5f36e673f318e8008b00247e6d5f86748d15e6adac333675906cbedeb244df62f10ce61e859c88c0ef00bdad36ec686e96235dc2477cfab0987b803e8b52bf6061a5ddc419a993548e00f2b87469939bfc89fe6225290d3f05fbf691667e8fb7411d48f05541945c4400f9da36f7c69129f129a454d5f6cfde06e7a6e722373452663268362b5e336d00ecd848daf66d7c2fedb670020f26e213bf3467398bd447624db575129134cb0005703b0cb10456126851e06cc611fbd3e3ac389f03a2df0d68ddafc55cfcc100d3bef6f5bee4f14d3bcca02c52163137e53dcb2b8a0315711591dd8b84622400e7930e23e27c8da4ce024c7d5cf9df9154b169722b1d9f6f3d00862fc4588e00f89835ca27441d0bab037eb636cb7eb684f5d126c850d0c68c98decb692ac00030c0acb9e24f295c0dfa49487a22d07166e3d3ec165708419b73c56031bcee000a9b7c37e49dcbde86d1c2d8fdace230533c3da287c56e6a143da76a6d824900b01e48d9ecb841040d4f574b9335602bc6a4d3794e263bfdda4cf20b2fc05a0018499f82e25a51e27df46cebea1fc78f346b5c05309d088f0da6a650d5fb08001aeeedac7d5e0ccdd67a0ee207a54059d8cf970842ec118aaca4608a1338180062f916b3fc04cd6f5508ec8e44b7cfe6967f9cdf08ec0388ad1fa5dbab37e200b833d3c82df45604a65051e64552888769ccb51d4dba4760dedd0dba7ed0170084c4c70e5be4bda029eb8fa1c893a57381cc8b51814d890f53add656e565040073361525678d2361ff3c91c4423eb5788e65f77c57a5aa0c574c47e46afde7005d95105f0ec7a8e9ade5c833a89f2cde9b80bb450ef1d0f21a067a9c508ca20037a903f920f04bfcd0995a2a83303acacba27c42936a72828f44ee6ee498720088e7816ee9969010dd19499b0e3d1b287b1e640c0f28ce9cce0dfb35f2b7b8001be3c6d4e33c1d217fcdd97b6f9e737ae539de68dc3fe82b04c487ecead9e5008961a4f7e6bffadfb4456204503b6cdb571fd651d3fc29b98ed730a8dab6f400a6d3cb12b903f76987c8fb1345e29268950d041658f7a9cd08155289c997f8000a7e1fce7142617c96c7429be4417ce0a7c0b49acd5e912121d42cff70daf7001effc24547b09a3a2730037a5dba6fead9bd703f5b2343deb795eff0a7955d0049f4c5669db52589c010f4e2406241c9d65c8ad14f69bb7cec8c63d4166f4a00f9f974a9dceb1f011b45af3d2565652f8566bb2e0829094bdb6f5073f2dfb0005a9daee79de035d499657df8ab596f182bf83cb9774c442a67f18e7a30dea4002ccf84264bd8c0e27be14c9967eda9e450a1aaa4ef5ba38993cc1ff4f78b4e00a12c0741bca53149590c77f7b74c5b36d34f003dd549e249c732313efd453b00ea1b0c4adbf0b529968ef12e413e0975894cb32d90b2a1387baf811b7b67290071ba477d7e6251c390d1ed645c56006a870cf540c015d254182cf6c2ecfa6a00347d711cb2da959181625f71889c3aa03ce0dc33fdba0b90815b37812f2df7005d6ca4e0cf89a63b1b493f9dbbdd5ae3eff0208c2310e49a75f6566a228907002ad08286a674488da2f5be6690f4adbda2b5fe3077cd3928ae0fb497820e7c00470f7b585470b2f41b077d1543c373b554a8f65bb8d000e598fca36cbc3d1100f0761a31fcd8b1d2855aed9feca88f0ce3aa81497ac8bd83bc0b534e8c694d003910a369a7a2e3c9eda356aafac15e20d3ad9c69caf337595d78a9e5bd776a008a8fcccfee98ca76f201448243c0baab051762a12e17fc64b5d00d84a72da5007e217ed04c90c991791c4197abb50701cdb7e48d783360e332d06719eaba50001e048e6a6825e7e281a0295872d646d244284db186614e63eb295f86ff656e00c13353f6f52856762f01716ed0b34674335ffcbef83cf9fe2524a6f848df1700845d51edaa86ab5ea659734ef75aae9418922dc425c1796baa10a996325b23008bc95e462e91ed771a01aedc6e0dc5064d0c4771d0040b0321dd990102dddc00bd7f61ff8a029a4519e93e160755e2784c5436fbcd141dfbfece514efa3eac00b3516fc7457f5ff715e24d2e578b3cf54c30ad2e799b845c56abf22b7097ae00e79509ece61934e00fa10d28f4997ac4a1c82bd9df56c4d52d6e3dd1b7ff9d00aecb5b70d37c28fd5cc08a4fc4484c7411512726768f0e3a56d0af46ffe1fe00ac3115d6ec640238da86162859549ddd995a71f5f5637fc3a497684d100a5f004b1a733a58e301a1561b48fae53353e0a1fe15a73c1ca8df88dd78b3c480f300c9938c91b918f22c0918759d9dc4efe86d6d04807d9f885d72be3a468d82a6006a3b284989a9c2c29c6fca5370a130340326c3845c97577b9c6988f62f294900dffceb89bbbf1ffab48a6dbda84b131ff1b00f2bf2e32f805a9970174583b500cdb9bfddc59eaa5530d9505e767c4224c72f274db16dadc0521eface0b94d2009f9e43e37ddcdc4d78e77b12b2d2ab3e69d7422dc2b21e35974f4c30d6bdf300c39f81b4e2dab25a8343a3fdf734e38ced5b50d34bbc56d1f2dc6feb2baebc008a04c65ec0ac98d1dd34c5e939b3332b1294a8e33e261a73cbb3362a7299f300db35a1e5eaa4658ef1843b2a15947f4f283a6c5c2ce93a78012c53d1f4fdc300366248c0d457b49744b2e70d0b2a32b42b49d31b84387b9bade30ed5e73b0a00047c7420439fabe0a8ee4e66af39491ba31e4f86c85ad3fe429c41c8285b9200696acfe066045b82a56fcb87bcf620c59485e29b0e921da1a9a5ef9db34d830037b088cf8757d1deec8c1c63f2a8a76f1146e63ff8fbe41b80bda976fe8732002b732dea63a9ff29588ca3c0472c14a765a93c9ac5c28b4b4bbd8403ca040f005bcad9f9f9c459dda0574c433fa71057bd33ee81d8c5c12290df52cf85692c00710bc9138c59b7819a6b9371394d383d5e2324ac4cf5b9e28ad31b04ca4dd0004bc6ffe48f59db58ba4319340c2f83c3c7642e663251a35c08cecc28fee1af006e2f9b744fbda8fd457009578b9910864c55b11eed81ec73b9493773ce6b260017abcd716f5d7f02c0096e680e431499ae1c520772fafa58e64380675fdcef00373a54a74eff10e3fffc4be2f5e15826af6f5584c8fb38a24f8c3a4996218f00effc6a0f732212f236bb93a0068e07a21624ca815a681b4a3aac86db6bb8a300a14f182b8e4aa5df41b62834a3be22096729be437a79ecf986d7bba3dc380900eb35d39967217b9646ad20aeca77805a074db67756c213627ae7cbc39a3fd10070443432041e0262c98a7bb90cf597f3d996cf27f952fd509734aecd7c3fa300c166597901c65e71eb531e043d1e3d495c744a49ddfb15776ce90893f5fab100b2f8d31e1f73af643aa91073da1e11b590b01e541ee75c914b32ce2f67f67a003fd5d06ba2d530fc6105c399bc65d3aea1846c5e064eb34eb65d4c28385b9e00a6442f437ea53ab065d885d265dc25c620d2654a622ab4ba7468aa6bed1ce4005b6b73956f85f77ee56b3a1e8f3a011cffaf50ef980427e7ebf148848ff131001336100928cc1849a0bf8ba65c2e16fed4fc1c087f0ea35c83878e953a0d6f0007bca2315a9035bed045cc03cc47a8bde6e85f5325c2a792f560fd8985cd5a00cf4affd3e01143cfa44bfb9282e4103ed8a2750b9a7a37647ce606097c45b5004115424d0fe50f9fa451ae05450bd1c71eb73c2bbb419046bb9295b346824e00e2628945330b9d99ffe31dca09a9f16598cc274c1891a55adcecbe9874a9250038be70dbe1e204c4859f63a5fa928a3e89fe45bb26a6ec7bacfebaba8b1237000cbbc59c0d6b8176d0f8e3d36efd889438315b2ac209cb96e15def610f22930057ad475661953707809eacd8fa6439fba0cdc344072625e2702b7925b669e800dc88bdc5ab4ee19f7a4ad65198a98754d3ba8056ab878fead989ac9896ca1e009013ac98b36e2d548eeac4f9b9512409fc89365509ef25ca4b3d085bf654b200dd632623c619a0377f52828bbd37e2151ec7063f4194e0042cc512b939e22300f566ad1250e74a4ae420de7b10172997d800110ef379b7e15b218ad4e7e81c00eaa8196174bd0ee2c64135f759eee3ddf409c8217fbd8a5634ab7c26574ea0007b06805e7cf605637fdf441182925af2f855079e3b1057f89ef8f0cab3c48900961f5248be54c7526de4407b9a7f13a1a77b9d077acaa686548ad0c078e196003d213e88b9c542a24c380c3e08e5e3342b2c993aad36e0ab5dc83a93fe994a00fdc2a2ff320f7b8454f70cc6fbcda44c2f07bc13273d230d30310c3982c3bd000f8be026bf380040523f98720c3315e447878bbc6bbb1d9c5491a839aacad500b6600434804f7be7c4a1a41c9f209cbf4c356e8624ae5a2055c1aeeb6ab90b00a08a5fa4204cadaf55426d3a357b27d797cc4d7aa15fdccd028557ee3bc6ba00ac6d80a4701ba62ea446561e98b2edbc52135ea4fdedf344bcdd7471d21b7a0014f30eb6ad56aac94032dee17f94b3488f47640fce735797c024af52d9736800dcb7f82d72478c82d59a7b32ef6e24429319ede1e9f193395d99c2b85117d2003a183f1203e976be51a3622314447a1ee1e998c300f6507657634a7fb85ccb002671f80c862a89673cb71a2f112d15c4d8b590da4d99ad5f6d7e7dadfc406e00a5babecbe955e093265c1e5a53d59e27b1e46888050a57d3a8649571cf61d9000f3778321ac908acf3dce51e1ee5631623275544a60bd51bdc12463e904b1f00c441eeaeca3d51162d0c49407b1c9c22e2d592286c0108164e497cb012566d0045838446b7be0d73a0f1605e51a35e6e501827585cc5d30c9f969555147a7e001603d60d7f586f468a257dd6a6771cf8fd9ca60b5f7fff0d2e4f99f061c172007a29e1a31727d853cb53d84cbdde7697fb7b2c8c7c9f8610a507c7b3a1cb000068be7ea1df5a3a62f6a360bcfc72fed6ade7ee9fd6eceda40415820919a52b00c10da180609c0d9b95bd7ebffa32b7084ae3134fdfaa83f69b2755a5a8256d00b96331af74b14e8eb44659c08bfc2cc781c0aed375263de5c19487740e4ac900a5741788998f0c3ce8d8768314e54c75578aaa650115e2bcd68f23b46ca20200c8883ad42e7f45f29547f4cdf5ede3a07e2f779114b4ea13a7a3efbdf0fc6c00fec6bbdbfd42c4f1b587f5b200227ef451bcf9610d3952351571dd0a9a09ae005716e7531c71aaf1b9c19b052cd614e64945027fdc1116ae26c992f9fe398000d58a889f21ad05bfba66872993a014f9d33898cc4f11a0815bd6df31fb44eb003b27076405da54ab958190ed9ab27fb81070a65a79a10ff9eb073047d382ba0088f12e9fc4556f6514758dc0f7b52935f18602d9214f5bcf824d51e1015dc100e3598c04e8d5025d5845f57cdc5a0ad7eb554f1f166c35f0f43fa141ac71520056e58897824ebd2b96c4399ad89aeedd45da773fd0833ab8d0ac0ac4111cf800f5b5e1fbf623a44e4c89caac18d8d11a78ad4f62f6f0c61146fc3ed0fc61e300a310591b899b7cf032dd4d7e2958bb100fcc77ed276bd9b2555cf8341809a70032eb1453c6c87ba162952402348e07719f51c3be2a0109db82616fdd99b87b00f67f59583111bff12523e7bfcdfad7ca300bfd6d65c7421fe2dbf0cd504a3a00e936424b8a7c63cd6b12086b256e79ca6ed067900a026edfb3ef37a7af144c0034ecfb3bc62f42b45e43299e4bca964b75ddf6b1c22263b4c3e49bed87a98300b5b896414eca441bd0b2daffb739e9bdd7c6f84eefc5ea69a48930d631014b00db176b3c3896bed2557aa5621a1c0fdc77cbc1aa990527ccdc2134a76fb4b800e46cc089a288f6f192cddee2ddb84bf5c6d133c5e6e63e2d4a372df6f6c9db00be16e7de3527081efb8a199b17e11445676a14a1bfa743cd4c77a6b9faa73d00dc5c7704997de1f8abe4537845249918f9e807bbfb4b6dbdc653d6499a67d80012015356be4c48287b35ca82c4f6544b33da12a616d08b841b7c0c5242d39100ecb94dbb3cde15ce5fd69b592d2760fd0d403ec047ab1c76ad830c8387362d00b08f6e9e403143d0e97ef8405976cd692f66c8d6c84a6e40705c515659884b00771af9a1f3ef3c77616a9d9d41540e416b83db9bb3e2b75d3c917d3de6ebba00a122a182487de64921e0f9f82674db37765b1ff31dfc943be53da2954b489700395ff91f6d11b792577aa1f4cd53fc78b0dbba37bff1762ebc8709a61eeb6b007de1fa02e0084340083c5b8d790cde11fa341db347ae9ec45f3af68d4f6e6b00b2b4c85f1fc63acc3baee2de829cbc33cc4d0cdd626c458675bb98fe46f7ac0021470cf93ac4a68c551ac214d87738af855a58c18c848882685fbf73aa710f00d0d1051e79891a207edb082901a7ea4f2c18a9b848108ed207625e7cf1153600ca150c325b9a11449f9f4edcf5eca0daa2d83915065bbe26d039ca63ee6929005de6b88da77b347c0e3edfc24cd91b45f48700de27e5dd3a104e92b6f367fb000f4a0acabeca6541239be13cc4832aff587da7bb5fb461fabdf8eae1fb3ba500a75f0016f2d12339a70a4f0b791ce73ca905ebb268fb8b800049086a7fd961006575db8e1999aed0d160c4d12ad408bc85f5c5e580a0597e747cc01d4e852d0063617f3b87bf66ee8f991e11116428e693fe507b52ffaf8e9221d5769c0110002977158e0c33891bcb2847dbc8f0a0dd682ab562b0377d9addfd465d53d36f0029f7f7a814392dbcabacfa7623118e642d4f560bcc3ce77896f9a1feab5a4200f6ae42a99d2734ac9deb71e078f34ba1459f0cec9a6445629439017ac84c8c003198f321e36849c9840d33550c28b2a9208572d053db5c0128e7a9f3a5ab4f000e030029807a45fa1784bc415204b8ea5851a1b49ba1b0f8f731e3645ee96e00fb30d342c0a4b98bf2081228e3c284aa5de1f6e81aaa93c3a7f7df251abf5c008c832a3a631cd7d142e74ead203105a81fe4f4fe171dd22fdb7bd1ef4e3f3c008c3f2b3fd6adaa1ac0f14914b3947d07ae27b07d27651b847a5e96e9920c61008952bce43ae15b2ba104b8099eafef0c0ea67e31a4129a9b5b57153e3b39d600402d8fa334ac6fad7e0142e8c22ec186f9beefec3421dbf6133105d82fe19a004f9ca0f9feb12f7b6775a9297eac5e7c2fc3d3e41ee7842228d5d51fd615b600fab8cc31422c7f542ba2162960e155273532a9c390c719ab9fc92812e8e4c000fa28f39b76bfee90a8e16c961d39efb874ecec1eff1b681beac67d7b3e368a009414e5eadd00d539ff2b2aec631e6bad7db2d939325bf259c9ae0667e23f8900a0c4c2ff4683ba6e8084b35e3c430ed9ee10f951669913e839b7741347a52e00adf1f60a995bae181fbc9a4d8778b3e42495d78d72bcb78fbc88573febe02d0072ba393dc7f12a257597fd2ea9b17fd436d4ed48cadd2dff1d316ab8cc4bb500d116bbc671968fefd7bf6450e77e7d7174c8bee3a0f55312d846a69bc52a9f0074ded2e5e57f0f8bd4c6942ab741208614e84686b4c10beec7a890b49b9ce200c3e2981dbb82b15226add2205b05ab547e9653e8659b6cde6d4034480831cd003c12b0bb94c4769b222aa0a267a214a55bc953306ac38dd23eae1736257c1e0017f7b51992bbe9f8199c74ca29434642517572e377c8110a2b077c482d28fd00a212c30a48fdcde7a3eead86618a4d76087ac440255b0808090d7d833ca56000ac7a879ed81a96a55622187785c94e999ac246902b883600049827dd8f825c00d7d5927a0c634fa2108cae79ab70700810217e8eaa2eb0a98a0a53778e63b1006e5c9a60fc26d3d4e5ab34f9308b9c045c7ffac84015a78c41c48fb409cec4003826dbe97c72b7d18ecdff776b7753438d3472bdaff2c1b5663439949acf4b007f071cf6fad7dc0bb77870d14a26d1827b74faf8b355d444be1304d4ee70b200e5a80357a5e7be0dc5250011ae6ed7cbaf0f593eee770c6b4a0c9a6c14e3c10073943143dcd8f19648ca076dfc9f1d650e6392da20769d2a6f605a3200cd990099085358dd809a5c7c54c130f57525531cbe6cc99daeca3d83463e1326f7d000bccc735f681a9412897f83472fa1face911f90ee86279c31a50ef3d17da47e001f84145e90421515e1aa7784ed3e3cf5755d7886ae9271bb4382ee96ed03cc004ffa0fcd501f23185ae2591a657cb965d63c9cf08c297d797f18e72fa86c0900ab7cc58ce0a6c7ccf60ba9ed9ba205eabecf0116fd21aff233be0a1643b9090054b36305310d44062aa171c9b3206b81ade413c2905da8493ca144d3ba0fb1005c605f0e461d290a7805bba3b990779d4a6dd7f855cc5f1d6ef5869cbd712000a386b2274779a403be1901814305ff339d75ca3532a888ea70c25a5372078500dcda2f1c0a7ff5abf368c7cece1cb5a29109d653fed53d2adb4d223a6a0a9d00072aac1eb3afb5572b8b82960760862bbfe378c37103a46911302f1ea74d5800aa57b1864b43190ff945be6042c61945222b9a2a12567a77563207ab3951a600cf4e45dfbb21662b73fb1b92a9360beb61497a4e0338d0b861393d4630707600c48f4da20f0deec4c9f03e80f151c6c24a3f37d268ca258ccb24a483daefd400271de815d4af6149007d0cc2ecac4f416ab42fa10df1c0514f15362803c5ac005ecc83c4a5b53f9537abb85249c590347ce0cbfd68dd1ab7b8990707002f010020d6401d5eee19e220d43430ffed2a1e320cc1af6da28e26577432ae0056380099030e8b4ffc6008caf95aae2bf1f9559ad08af926fed01c6246f71adf91ab00ceeca89e4d5c3d3452bb667d14dd0f099728f01aeb802a9ef72365c6d3396c009cc29b316b2411354be2c6ecf74dd8e60130bc1276a19d185706888436be0e00b54ae3224afd2c9d571748ecf33378e714a5981e4914f73842753043a047c400c9d2def1b299934fdd2a7ce7c666536e1c934efbf630dc552b30754dd9bcb5000e231a7113c8345347ce1172aa6ad59e8cd2faaf42bc50a666b04210455af600876b16277e219f65b6cf3c45b0bca33c4e8c98de1df56ff216eeb77934fcb300e620d720390fe28ded7b9c2aa0047e1d2f97616fc9377dfd17b884fa14a6de006b3ec8f3db3bf23092ada8138dc6c4f7cda5d34bb030878244a8d20c9731780053e8e1082da049bd1e56f167b6cd5b8c1dbdf5d142108caa6661715c2b4706008a2960935a6c7451a2e28384870bf46bcd2b1982add24893021332996879510090c8c06e33a868257a71a7d1e908d8732dbd863d1570ba09bcdae39051144a0042ec84f3fd9cc396c68ba76ebae2a568c5d9c2ef5255add7ce7fcc85fed89100588076671b20abd42d0f1965dc0e0a02e441713c7e36259b47bc977b0bbf31009c9f2f007623ca2abbad8b3e1b2649afec24600e53beb2847197740d036f0000a0559a2e78e6dbbee720bcad36e89955439a66beffbfebc6a90c218a7e6e170045e3c7d6353906a9780a68037db48e358fcf91a54e13606b3f2439de336ff1000b8ad804b79f195bd71fd3763c1e28a20877c55ed01e4829ef078b18a1df33001b487207833f3819de7f870e99291105371db278af5328b88f59915250dffc008b8b41a7ecc5334a4c27c0caf1e9ce4ad0e411b7c48cbecab3d718eb7ceed10070f350cbd26acdf6c3e8e1ba1ca16c3ae29acda8f35ae814bb271f0ce4df92001ac6c44957089b57c1c3992ca8916e98aad28bf89a7eaa2a74f43082af2d3100cb51d6ea54b9705a221cf6e1abb9e894ae46c727d1847eb594c9cea1a6f02d0047deb350cceaaca8a720fa5fbdad056c29bf992854ed41291113dea700b8480027a4eb43e38c080d1b5c082a5c4c2c8c5fcf22ba51f37754839e11f1f435b200e1f10d8fde9997f114cd36d967c94ee727da72ef5b2b5d2c2b6e08a98d85480038f6eebd7307d0b83f31e4d49f2f00ddc78b9d4ef868478919b1962eceecc8008bf2cec0d18318e2023d9f84cb3bacf847319fe5235f1adf8fe746b6d88f4100cec448c0c2b1cd16f447bb07dba3939581befd216fc77dacffc7e69aa5dd9100c7d27592e986c240ae14431dd7fb2709bfbfa66e980f7632b76a2cff798ebd00edb182aff1c10e36898276f4634c856ce96e8b531b86d852e341d24b2c3617006615f61c6cc58015e879f2d2d5e5be4a7b7d55c016293f960a7709d3f981b100cfd0263b1b477fefe2ca04363039e7efe1719751bfc2336841a67b1fa4727000c365e0c50f2435244d7ef02b8b0a6b11e4a9920e92dbc0d398ddc9c54b95c0004306333a2776697fee621cbccf6edec722da791cbaf26580f9dc5589c7d33000c72abaae3d5c3ccbbd6cb19dc97df03bf8ff8a2f29b054ffbae2fa807e2fce00b169dddb71a37d65243283850e26340cdde73270f25cd697f9e5fb0ea0155000976aed56867d2f5fca587190f92ecfe1ba768bfb67ae65deab2cc84298499200e168014c1daaa4179232567a493ec4339e202ad69175660f74da8036a5461f00f8e56bc2df878b6fafcd883c6aee8fdad9041a57a69ffb6e1b8153afe4254300497d927c87b8627d62585699cced7c3837dd6f1f1b7fa97a2d2f0485c3d6af00cbfdb2225a21d920e9bce0314d2ce5cfc87dd6c95b16777fda2e6379a6d28200f9240ee854bb1f92bedfd7f656eb6d26650e176d19b7abd4a17bf1802591fd0078996be22be2a238dae0e4480314c5e77d49bf13b74852f4823b310d40a1380046905be36f3f8a05accecf41d6bfa7a0393b55dfab6f85dbfe754440acdc60009c73f5dfbfbc7e3fb0dff2813fba27745f3945324c6bea4760a9bdca7d5b3b005eab9cf5494665ab7a18b06ef296f6c731b48091061649f25924db68d8795900a2bfd8f327db9ae7890e74d46edb3e792ab85e11df364a4cf7375b5e2007da0045eb3d774cf785b15ab8593c15f42ba747a4c7d313893626410d69098d0d5100946b74d40db3e2485c2b663513dc97285fb8a543eb304869e3b07481483cc3001b2de037fe53134d185d79e6fa4f9a8c79dea5d5dab84fb02d1568fa78a5fc00b7171e6f55fae0f62627e4bb2b8f90e7bcaaed82260db1eeba20bfb67f89c50073a3c296cbd0ecb7400d2b20cac4286676487dc1b641033bc5250bbb0e269900223ccf9b1ddadf662ac2f88756575ef9d692906d8fa0fc6421c72dc08806b700027c021c3f8950de74f18ce8f09465b483e7749869f37cc0f20a9149a60c4d00796bc546b3e34497c4e684a3949284f5a03d746f3f8633392e489883e5930d0062ca34458def10adec6161a00e9da82d32eda4f2b638f76ce6adc162f44662008ef6d0f8cf6027369f00789e8874c43d1a9d61575c461830c644f41369e0e70040f51a25c71f839ea7dcff934383c7563bedc33c0e07db0932cc539b5a8d4500e3e64184c7f64ba864720877457024a52834a06310fbe8c090d755ac0ff53f00709357ad4bf005f7b0c0d65d9ce7b3239dac8092f42bb2c5fc161026b97609001766ab410025a527de8f9856a4a88fb2e806ba2131dfe2b1d4c363f880f49d005ac23536cb52603523fb1304925b123f6f97467c6cad41da62b0f49aa3a807006c3f67f1c0d326585f746ae7c39ee87494808affbdbc91b7adcb605b09eb8400229f5376049476f253c8c43be70534dbc24825414d79bb8fbb5e8729db84670009c92ab497dec117504408f277df320b510baf78e069ed48a28b0282c57de0006d02a897610eeca8ddfa8c99d2536e91e08d7f8ec61772dfd68463a210a3e300f39bf43b70f15b2f809c0c0b3d6c471b010fad74f5e2a21d5dea4844d9d3a7004e0e17ea2d78669f2e58e5c77144301acd90728fbaeeea4db62a0c753d0d3900a73cec1305a3e1b09d396142d4493134f02aa9426e3dec5152b138b7525a1d0088ab7710b7dd88cefa21ff2d2049829457e576b2c79d3cb5a20dec0726c5e500f7547ec48e8de9e86a310e6da81a93f1eac0ce8f352876f19ab6e9c2e6876e00de314a61ee89d13a1f9efc05cdc8fdae224934c67d552ff5a570ae96c26e7700164077026243791dfc6f2e9138a3a94f5aa246abee4d1e550a35ba27ee28df00efe300feca451dc4e7bf85687c206b04a2431b6813f84884c7f350115847e20087713eb6e819cf014bc6199305472d193ce6f3fa10e04650ec77d2136ed28000f3817fc325c660b163ff285326a096e6cfa52ab68fd797e12c925c007672f800e680ad044edf7ae18a319d536dc5e9e58d45782282f4acc698c460a291a4b500a4cce226300d0c7ead11dbb9f589745ea37c5df117c40a2da1c56c860284ad0030e1ddf7124b2c496cab8b4e885d68d384b7e9af81c3507b4fbc4bd854af2a0031873a9471d13db154f995c4771f3aea58794655ac7ee6d9fabd0934fde8e600b13c7a97fec6039b671d4a17dc715fd4012fd8cd8a9487b100ed27e5858d6f00599bc20fc1f9d4113ea20fac2c3c9d8ac9774887919aa179a8227dc500f0b20084dbd846f6fe4893ef0a8f3b1ae2cff258aab7a79e19286bd6fb5e8bab8cbc00512f01981ea0a45db5033eb2670b8f4c99a383a977e4b59393fcee25ce54860073bb21f6762ec10af582a04ca49e9399f519eba48d1229121b3e01f19ad5e9007df6176034e9f8fb1990f5d61d7f983e49ed2b0aec0d241fa9f50aff0437500017b6dbf87d9572c3429747758a1b1f44ea0ab755d599ba122f4ab9d85d2367006792ec29c91aeb814a6000f2ad7364746a12aafc3298fd04b9d3cbce9d55ef00e29b4a1c0185a3bbf5e729a8274136290152a491e7ec68b1e48879d03ef024002398d4a057e3ee68c4745b8e5add41c90a119364e8159788dab7366abac45c0043c53657c0dc7e5b85c8bac1c4e7350df7a06e11d6142ae800ad028ba3f1110035fc05d251388b27a428f2a29f100894132099a3f84cc54a5cd1ae700c9d9100f6ba9ca0531a1cb787864a05db1048a1032bbb59fc7cbe82ddc8bb12ffa1c000b20cd261bde12282f5a28d219f598b3faa6de3f88a5c726a7e97a0238ddf320081081fae63b1f5c39d95fbb5820d1774de42174c746d233364a93d8e079c7c0015ea3c9a33c19f119596a0d51d636614dfc45c97249bd43047fea567958098006ea9fa1b84e301648c05b927aa6638c77168a975077c1e3a8bd9300dda042200d1db17a8de9cb9dfae4904a31d0bf3b9a5f5e64e8c2bb5582fbfc27537876e005131842fd5612cf587be02776edfb23dddc32012fb0ac0a64d2cba50f3ae0d007bd613d373ffd260bb3bcdfaedb49fe5019d71d6cf56b94d147dace15cb21c00722d3a108885ceaa66525b29c208d7b791b23a3d4a32bf7f6db2523dc99b7a00020197a843d674e27558b6fa4eee5a1b3d7b0e422689a62bf056053f8c33e0003937ffc58f732f0ba027516e4fb11649aec1d933da02cd1b7861e97fc53384008f5599617e81fbc3fda191d6bcd882efdb2874dd5203bbe8b8e5bf9cf60fdf00e15ce5b1675829fa737a4eacceb465ae1d8d36e47a86b70d38da80fb93f752007375ca360b15ad0907cb9028705bcdc8729d0ea22ee08c6bbf905c4d538e2600c3c509b2460aa9ec9def71561fc9523b6f71d6aab1f901cf790a7fe82e4bc9001c2b6d60f8205cf78a85ed0fed6cbc8a6dfbeeea289a1e72bdcc0b36b3864f001a2a041dd946fac3ef5f93f92e6ac0664a5fd444746a702f8d1b92de654caf00673c190a15bdcb2ec1b35b139f1d1ea8180260799ea20081e1bb90ccd8115900f807195f1ffb1554185809048d8a0cf90d53cec597961dc710c889001da4e000224bd92f23c7d5c245134d28242c962afae896728827da71b8c5da6552bc2b0095c527c80e90e9ec13eddcc083a7c696b8bcb2c756144af0b4db75558c98d50041956cf82fb33c8c30b13d107961c3236bcfcd15b4d2c65205a170a0d3eb77001de7334471e4769c6e0ef9a4052102918972433a7009dfebc639f0788c5fad00a4795f067fc5866921386fa367562dadcc5f95e83019e910d914756cc7d8e2006f410b05b038cb1302cf53adaade003aa5f1ad7832bde0f29cb520d9d5ca54006ac1d300aecb908e87b44ac108ba8ba808b808aa30380017671f6457d06e1600bb0f76690c251c5b414380c41a24e9a940228d208cb651faa3eb6613898d2b00641e2983aab388b5455aa6341abf55f91d15a54e8b2455b07acb934c121abd0082a6dba7e125bb919ce6afd0cdd682a19c0d9ddb21bda0e36edd9455d4b2ad00c5eee6a1fceb1c0a902c10f049dd8daccb31988ba0f7f7dc461475334e5b22005f9ca86c5d1c02235253df17435a1585d54f79d8a15b0a4063aae97ac8249500be7a32c187037348ba10bdae522c03e9235ef5e122fdb0e5eec0a88fb854010040da616490ba27ea9c728b85d5e2d6b0ee09a863cca9608e19b19c6ef9d1d40020268ef86c69c306aafe0ef6d2999e218b218c96021780ee6eaea03dd0ed8600796fa4b243389ee0ce031c29043e8494ecdb7beba5b5db4fe8e78b886ce98f004a94572e90b54b8cd8d3003430fa25b651d387bc4ce7a34c702638735738ed00a8df3e42ef32c6601ac7a046730f4c468e1d34b82591b680624f3dcb60a2ba008b7a40142cb24cf2a91b6cf6fb4a67204b03eb4d19d1b77584d564cf2ed87800d43fd641cd86ce06792ed1f091009f72e680e5b33aa2c8166fca864252513400b74b821e49b075e04b462992a5a2c2264b2b02722213c99f48e34280e80996007da383441bcd481e613a860aedc2885c8bf85cf08d67d56ed14106c98fc11e009f948d7204bf869d13b17be572a219a27b6308360bb669751299a64b78900300280471d8e831a57f85dec4763bb4a5333fb960e06037277cd780500dbcd0cd006532d826c48e037cbc8c30720d69744c65488223b78ae902fccf0752c8460f002dec49745ebbcf0208d288c549e276f82bb17b9c78866d4892b3cfd7c2ebe900f8341bd6bbe4e3c6a9600b9b797c627a04708f2a2fe9252ee8f3b85d99c31a00c507ed39c7ee823a0fb5388dab2b85c09f40112e2714588151e412906634d40014c2f694a2b461021ce65fd18aa398830a6d9779804eb44c4bb902aa2149190003186d83cdb6aaf2d2ad5ebaa00ce07cf2a946e353475fe6aad812bff9099000a450cbbe48364ad42e29bb75d77bfd6bacd6bfca6ee7d462142532aa30d3a20049e1f90a16dbcdce69ae5f854f483fa3643920668d49944612a5435559d0a10053f15be586dc46aee842dd8d55f2e64642dbf7d79448c85da12cb805e4bdb80057a85b04f2659c143988e286b437cceefd7744d3604c17bef3676b105727b6002b58f8b84fd7f69850285b9ed113e8a0b05df95ee4ac2ae5ac1c959ed6cf0200739052572ab0b0aa3a7123605b28e3d5fbbe587c3b1fc81f88a8e0ec89f5aa00871325f8c07f06c4178949e3d2d40a6fe448bf0cbcb246bc8a6c23758045ea00766b8f9ecabc276ed604830daa41f9948329bc5b799f68b72c0f939433d351003b46666c7a367eb528d8bcef2d6ffdc9d57d07bcbcdf63e2b8194f94831ab600f9706c35cf01690e995d0937e074fa821985d6604aa5127fd0b7f57ee839990021ce286d39a9e7f6f9238f58fa9c53d9dece7374d7f567cd28a1a266babf460009dc6c05f95d007a01a9d8d83737b8bbdb80041c59d4352518a081ed189b91007b530533e2705c76aaa54a8be959296b23e563b5a20f379f3fee9fec45ba6f00b6c50fafe9f3caca9cee93e3625b3a55be6cddf1a2c1775e1f0ff29658ffea00b563ca6001fce8905971911d2c4013cc154f00613950d81db6e868862e3f7100254b336abc9871a60228bbd0f4605af055a62f7c0684c0e8471acb967096a900f52ce17155d3a7635a6ac45ae79c9eb9332595b8a83c241af3a09c22b8362100e3043e919220bcf4fe6f9da06f4a8ac9c43aea094997fbe9b7d1a2b7e93c880015263d66fbf68a2f6254c6712247dab6a7517f2ad423dcb27877eea4aaddcf007177d7b81be133b498431c1fd79442e4b7bff2e74cac64081eef72fcc71f510072938d75e4247109a15edc562e1f4423bd8339297e8ef9b10ec4c46dd05fdd00e90cf6733b87bebd0dd8e3c4e769bbbeab2697b36f54fde48c866255b2f4a70097779cfa66fe1c6e326838f140edab551ea9ab3f7c0930ef7021063029bcde00a07e3ec10dd3f2ba859ed6d58e3035256c27ae64f8a6bb6ffd06893e687f4800aae559c36694c5f0c947c4eb911ba75185d39ed648de384ebe2cc9991870a700a5348a79e00a572a375c76cc78e88e1dd7d3d1edd569ea3fc61803a6e5c4500008f2497ea7052e3cf9b9adc9e8f47b07f32785185e96fa49534677fa3b4bc400475bc6b4d0eb7361fce69767833cfbc4983ca40563d6e9cd6244caf4c57a4c00720dbf90ed582db5fd650b793e370039ea8c3331e659f6d48c4b48d8896d290046ecea09c73f993922370d1d56c1b0b5f2f06335a66221b65c1298a0935ff0006d2abc3a007206396b64d6358fecbe1597ad26c4f536636564d3285e115b4b00ae696ca858f8f1273eae729f28f470b457cd1d60a4b9f81b6c4d488c42cdc50090a3b92ab04fe790bebc63f8dce8cb1c474bb179437c5bfa733dc13d69287500f134c013912bff4179e667feef10dbf15a319dac6ad2c8053a2356ee02f94b008e416748fadf4c40a21bb47f8102904b0c854bdeb9be41c4a0991f876b79a7001dd7da77ee9597647a0eb8c59bb5c7e1871d66a34bea3ef6cec4815ffdb23200315abdc386097ebb5c978439332531519402d39aae5df9496033772003368a00caba35beb5ac99c4dc7ccbf30d37c100cfeb5643c162006ab7a1d7d4a8700b00fd8198a6b8069a7c907f9f8010540c1919c1c41710429216c8ade8c045c4120083736320ce96d48c4ebe54a1e8574eb391526046ab9bc77a4efa3578c1e6f3000acd7e7e48a3ec51669581d658a309b79860e381535ccc5cdccb40427f8cb600cead15721322b55381924a54323e995ec598b872d39407a714c60de681914600daaccd4b51d3b80095ec4e566e14890dda089462f50982e7123432c54e8cb10025f5d3997177495034738e57d297f5d4f27933ff309fc1e672c007489fe182004b5aefb30542470c676e496cd1b42b20137dae26b27b1c61688d084277e13d0015e2c105797dcd1b3eec64c2c05650b09f6e42521634fec0aea92a8c0a44a300b40ea0a2e744c197e649822e4bb7e30398d68d2fb518710313f094a1a9a3730001ea7cad828423726ba1528a406c551a6498ab0f32eb266f9008a24b83c2ea0043c0538912e8799cae0e07467ccc1de500cddd5d37de67418f21de8185f8ef001d72f87466db7362f38759dcd2a1325beb9e91f168503016037d68a99a52c900a95b5f06afffd9601df9253dfa74aa64201fd49c4a108c48397d72659e9955002060511ed67b9e8b68faac3ff75f14987d8aae7eccb0df3381f4c96e9a06cb00b2d106fd522f5dfcda308a75c2299d01f02d56228500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f1b08d0960141c238395fc463bf31ccfa1d0a21216cb4fa534a780b6acc6b56d2345d220937631e790b2600d4c9b117a5ff4f1b090beff273125289d9a65a7926bb5faa8dad9728685a97f9fb0bcaf99f3189b1301a56f09910b9c7566bd3a690f661632 \ No newline at end of file diff --git a/crates/rbuilder/src/backtest/execute.rs b/crates/rbuilder/src/backtest/execute.rs index 1a192e7e..cecf1904 100644 --- a/crates/rbuilder/src/backtest/execute.rs +++ b/crates/rbuilder/src/backtest/execute.rs @@ -10,10 +10,10 @@ use crate::{ }; use ahash::HashSet; use alloy_primitives::{Address, U256}; +use reth::revm::cached::CachedReads; use reth_chainspec::ChainSpec; use reth_db::Database; -use reth_payload_builder::database::CachedReads; -use reth_provider::{DatabaseProviderFactory, HeaderProvider, StateProviderFactory}; +use reth_provider::{BlockReader, DatabaseProviderFactory, HeaderProvider, StateProviderFactory}; use serde::{Deserialize, Serialize}; use std::sync::Arc; @@ -109,7 +109,11 @@ pub fn backtest_simulate_block( ) -> eyre::Result where DB: Database + Clone + 'static, - P: DatabaseProviderFactory + StateProviderFactory + HeaderProvider + Clone + 'static, + P: DatabaseProviderFactory + + StateProviderFactory + + HeaderProvider + + Clone + + 'static, ConfigType: LiveBuilderConfig, { let BacktestBlockInput { diff --git a/crates/rbuilder/src/backtest/fetch/flashbots_db.rs b/crates/rbuilder/src/backtest/fetch/flashbots_db.rs index 79106768..34a26822 100644 --- a/crates/rbuilder/src/backtest/fetch/flashbots_db.rs +++ b/crates/rbuilder/src/backtest/fetch/flashbots_db.rs @@ -8,14 +8,13 @@ use crate::{ Order, OrderId, SimValue, }, }; -use alloy_primitives::I256; +use alloy_primitives::{Bytes, B256, I256, U256, U64}; use async_trait::async_trait; use bigdecimal::{ num_bigint::{BigInt, Sign, ToBigInt}, BigDecimal, }; use eyre::WrapErr; -use reth_primitives::{Bytes, B256, U256, U64}; use sqlx::postgres::PgPool; use std::{collections::HashSet, ops::Mul, str::FromStr}; use time::{OffsetDateTime, PrimitiveDateTime}; diff --git a/crates/rbuilder/src/backtest/fetch/mod.rs b/crates/rbuilder/src/backtest/fetch/mod.rs index bbc01a6d..ce173d26 100644 --- a/crates/rbuilder/src/backtest/fetch/mod.rs +++ b/crates/rbuilder/src/backtest/fetch/mod.rs @@ -239,7 +239,7 @@ impl HistoricalDataFetcher { info!("Fetched orders, unfiltered: {}", orders.len()); let base_fee_per_gas = onchain_block.header.base_fee_per_gas.unwrap_or_default(); - self.filter_orders_by_base_fee(base_fee_per_gas, &mut orders); + self.filter_orders_by_base_fee(base_fee_per_gas as u128, &mut orders); info!("Filtered orders by base fee, left: {}", orders.len()); let mut available_orders = self.filter_order_by_nonces(orders, block_number).await?; diff --git a/crates/rbuilder/src/backtest/redistribute/cli/mod.rs b/crates/rbuilder/src/backtest/redistribute/cli/mod.rs index 10dd6393..5c72b5c8 100644 --- a/crates/rbuilder/src/backtest/redistribute/cli/mod.rs +++ b/crates/rbuilder/src/backtest/redistribute/cli/mod.rs @@ -11,7 +11,7 @@ use alloy_primitives::utils::format_ether; use clap::Parser; use csv_output::{CSVOutputRow, CSVResultWriter}; use reth_db::Database; -use reth_provider::{DatabaseProviderFactory, HeaderProvider, StateProviderFactory}; +use reth_provider::{BlockReader, DatabaseProviderFactory, HeaderProvider, StateProviderFactory}; use std::{io, path::PathBuf}; use tracing::info; @@ -117,7 +117,11 @@ fn process_redisribution( ) -> eyre::Result<()> where DB: Database + Clone + 'static, - P: DatabaseProviderFactory + StateProviderFactory + HeaderProvider + Clone + 'static, + P: DatabaseProviderFactory + + StateProviderFactory + + HeaderProvider + + Clone + + 'static, ConfigType: LiveBuilderConfig, { let block_number = block_data.block_number; diff --git a/crates/rbuilder/src/backtest/redistribute/mod.rs b/crates/rbuilder/src/backtest/redistribute/mod.rs index 84aacb63..f613b091 100644 --- a/crates/rbuilder/src/backtest/redistribute/mod.rs +++ b/crates/rbuilder/src/backtest/redistribute/mod.rs @@ -24,7 +24,7 @@ pub use cli::run_backtest_redistribute; use rayon::prelude::*; use reth_chainspec::ChainSpec; use reth_db::Database; -use reth_provider::{DatabaseProviderFactory, HeaderProvider, StateProviderFactory}; +use reth_provider::{BlockReader, DatabaseProviderFactory, HeaderProvider, StateProviderFactory}; use serde::{Deserialize, Serialize}; use std::{ cmp::{max, min}, @@ -125,7 +125,11 @@ pub fn calc_redistributions( ) -> eyre::Result where DB: Database + Clone + 'static, - P: DatabaseProviderFactory + StateProviderFactory + HeaderProvider + Clone + 'static, + P: DatabaseProviderFactory + + StateProviderFactory + + HeaderProvider + + Clone + + 'static, ConfigType: LiveBuilderConfig, { let _block_span = info_span!("block", block = block_data.block_number).entered(); @@ -483,7 +487,11 @@ fn calculate_backtest_without_exclusion( ) -> eyre::Result where DB: Database + Clone + 'static, - P: DatabaseProviderFactory + StateProviderFactory + HeaderProvider + Clone + 'static, + P: DatabaseProviderFactory + + StateProviderFactory + + HeaderProvider + + Clone + + 'static, ConfigType: LiveBuilderConfig, { let ExclusionResult { @@ -549,7 +557,11 @@ fn calculate_backtest_identity_and_order_exclusion( ) -> eyre::Result where DB: Database + Clone + 'static, - P: DatabaseProviderFactory + StateProviderFactory + HeaderProvider + Clone + 'static, + P: DatabaseProviderFactory + + StateProviderFactory + + HeaderProvider + + Clone + + 'static, ConfigType: LiveBuilderConfig, { let included_orders_exclusion = { @@ -620,7 +632,11 @@ fn calc_joint_exclusion_results( ) -> eyre::Result where DB: Database + Clone + 'static, - P: DatabaseProviderFactory + StateProviderFactory + HeaderProvider + Clone + 'static, + P: DatabaseProviderFactory + + StateProviderFactory + + HeaderProvider + + Clone + + 'static, ConfigType: LiveBuilderConfig, { // calculate identities that are possibly connected @@ -954,7 +970,11 @@ fn calc_profit_after_exclusion( ) -> eyre::Result where DB: Database + Clone + 'static, - P: DatabaseProviderFactory + StateProviderFactory + HeaderProvider + Clone + 'static, + P: DatabaseProviderFactory + + StateProviderFactory + + HeaderProvider + + Clone + + 'static, ConfigType: LiveBuilderConfig, { let block_data_with_excluded = { diff --git a/crates/rbuilder/src/backtest/restore_landed_orders/resim_landed_block.rs b/crates/rbuilder/src/backtest/restore_landed_orders/resim_landed_block.rs index af69dba0..8edbfdab 100644 --- a/crates/rbuilder/src/backtest/restore_landed_orders/resim_landed_block.rs +++ b/crates/rbuilder/src/backtest/restore_landed_orders/resim_landed_block.rs @@ -6,10 +6,10 @@ use crate::{ utils::{extract_onchain_block_txs, find_suggested_fee_recipient, signed_uint_delta}, }; use ahash::{HashMap, HashSet}; -use alloy_primitives::{B256, I256}; +use alloy_primitives::{TxHash, B256, I256}; use eyre::Context; use reth_chainspec::ChainSpec; -use reth_primitives::{Receipt, TransactionSignedEcRecovered, TxHash}; +use reth_primitives::{Receipt, TransactionSignedEcRecovered}; use reth_provider::StateProviderFactory; use std::sync::Arc; diff --git a/crates/rbuilder/src/backtest/store.rs b/crates/rbuilder/src/backtest/store.rs index 4ec5b860..61b2a356 100644 --- a/crates/rbuilder/src/backtest/store.rs +++ b/crates/rbuilder/src/backtest/store.rs @@ -621,9 +621,8 @@ mod test { SimValue, }, }; - use alloy_primitives::{hex, Address, Bloom, Bytes, B256}; + use alloy_primitives::{hex, Address, Bloom, Bytes, B256, U256, U64}; use alloy_rpc_types::{Block, BlockTransactions, Header, Signature, Transaction}; - use reth_primitives::{U256, U64}; use time::OffsetDateTime; #[tokio::test] async fn test_create_tables() { @@ -745,7 +744,7 @@ mod test { excess_blob_gas: None, parent_beacon_block_root: None, total_difficulty: None, - requests_root: None, + requests_hash: None, } } diff --git a/crates/rbuilder/src/beacon_api_client/mod.rs b/crates/rbuilder/src/beacon_api_client/mod.rs index 402e1cfa..59e3acc9 100644 --- a/crates/rbuilder/src/beacon_api_client/mod.rs +++ b/crates/rbuilder/src/beacon_api_client/mod.rs @@ -1,6 +1,6 @@ +use alloy_rpc_types_beacon::events::PayloadAttributesEvent; use beacon_api_client::{mainnet::Client as bClient, Error, Topic}; use mev_share_sse::client::EventStream; -use reth::rpc::types::beacon::events::PayloadAttributesEvent; use serde::Deserialize; use std::{collections::HashMap, fmt::Debug}; use url::Url; diff --git a/crates/rbuilder/src/bin/debug-bench-machine.rs b/crates/rbuilder/src/bin/debug-bench-machine.rs index 623ae841..de56509b 100644 --- a/crates/rbuilder/src/bin/debug-bench-machine.rs +++ b/crates/rbuilder/src/bin/debug-bench-machine.rs @@ -10,8 +10,7 @@ use rbuilder::{ live_builder::{base_config::load_config_toml_and_env, cli::LiveBuilderConfig, config::Config}, utils::{extract_onchain_block_txs, find_suggested_fee_recipient, http_provider}, }; -use reth::providers::BlockNumReader; -use reth_payload_builder::database::CachedReads; +use reth::{providers::BlockNumReader, revm::cached::CachedReads}; use reth_provider::StateProvider; use std::{path::PathBuf, sync::Arc, time::Instant}; use tracing::{debug, info}; @@ -117,7 +116,6 @@ async fn main() -> eyre::Result<()> { &ctx, factory.clone(), root_hash_config.clone(), - config.base_config().root_hash_task_pool()?, )?; let finalize_time = finalize_time.elapsed(); diff --git a/crates/rbuilder/src/bin/dummy-builder.rs b/crates/rbuilder/src/bin/dummy-builder.rs index a5d7644c..cb09bd0b 100644 --- a/crates/rbuilder/src/bin/dummy-builder.rs +++ b/crates/rbuilder/src/bin/dummy-builder.rs @@ -37,10 +37,11 @@ use rbuilder::{ roothash::RootHashConfig, utils::{ProviderFactoryReopener, Signer}, }; -use reth::tasks::pool::BlockingTaskPool; use reth_chainspec::MAINNET; use reth_db::{database::Database, DatabaseEnv}; -use reth_provider::{DatabaseProviderFactory, StateProviderFactory}; +use reth_node_api::NodeTypesWithDBAdapter; +use reth_node_ethereum::EthereumNode; +use reth_provider::{BlockReader, DatabaseProviderFactory, StateProviderFactory}; use tokio::{ signal::ctrl_c, sync::{broadcast, mpsc}, @@ -87,7 +88,7 @@ async fn main() -> eyre::Result<()> { let (orderpool_sender, orderpool_receiver) = mpsc::channel(order_input_config.input_channel_buffer_size); let builder = LiveBuilder::< - ProviderFactoryReopener>, + ProviderFactoryReopener>>, Arc, MevBoostSlotDataGenerator, > { @@ -160,7 +161,6 @@ impl UnfinishedBlockBuildingSink for TracingBlockSink { //////////////////////////// /// BUILDING ALGORITHM //////////////////////////// - /// Dummy algorithm that waits for some orders and creates a block inserting them in the order they arrived. /// Generates only a single block. /// This is a NOT real builder some data is not filled correctly (eg:BuiltBlockTrace) @@ -168,19 +168,13 @@ impl UnfinishedBlockBuildingSink for TracingBlockSink { struct DummyBuildingAlgorithm { /// Amnount of used orders to build a block orders_to_use: usize, - root_hash_task_pool: BlockingTaskPool, } const ORDER_POLLING_PERIOD: Duration = Duration::from_millis(10); const BUILDER_NAME: &str = "DUMMY"; impl DummyBuildingAlgorithm { pub fn new(orders_to_use: usize) -> Self { - Self { - orders_to_use, - root_hash_task_pool: BlockingTaskPool::new( - BlockingTaskPool::builder().num_threads(1).build().unwrap(), - ), - } + Self { orders_to_use } } fn wait_for_orders( @@ -212,11 +206,13 @@ impl DummyBuildingAlgorithm { ) -> eyre::Result> where DB: Database + Clone + 'static, - P: DatabaseProviderFactory + StateProviderFactory + Clone + 'static, + P: DatabaseProviderFactory + + StateProviderFactory + + Clone + + 'static, { let mut block_building_helper = BlockBuildingHelperFromProvider::new( provider.clone(), - self.root_hash_task_pool.clone(), RootHashConfig::live_config(false, false), ctx.clone(), None, @@ -237,7 +233,10 @@ impl DummyBuildingAlgorithm { impl BlockBuildingAlgorithm for DummyBuildingAlgorithm where DB: Database + Clone + 'static, - P: DatabaseProviderFactory + StateProviderFactory + Clone + 'static, + P: DatabaseProviderFactory + + StateProviderFactory + + Clone + + 'static, { fn name(&self) -> String { BUILDER_NAME.to_string() diff --git a/crates/rbuilder/src/building/block_orders/mod.rs b/crates/rbuilder/src/building/block_orders/mod.rs index 6a213c1a..5ea4c905 100644 --- a/crates/rbuilder/src/building/block_orders/mod.rs +++ b/crates/rbuilder/src/building/block_orders/mod.rs @@ -15,9 +15,9 @@ use crate::{ primitives::{AccountNonce, OrderId, SimulatedOrder}, }; use ahash::HashMap; +use alloy_primitives::Address; use multi_share_bundle_merger::MultiShareBundleMerger; use reth_errors::ProviderResult; -use reth_primitives::Address; use reth_provider::StateProviderBox; use prioritized_order_store::PrioritizedOrderStore; diff --git a/crates/rbuilder/src/building/block_orders/multi_share_bundle_merger.rs b/crates/rbuilder/src/building/block_orders/multi_share_bundle_merger.rs index a8a86bdb..16d8636f 100644 --- a/crates/rbuilder/src/building/block_orders/multi_share_bundle_merger.rs +++ b/crates/rbuilder/src/building/block_orders/multi_share_bundle_merger.rs @@ -1,7 +1,7 @@ use std::{cell::RefCell, rc::Rc}; use ahash::HashMap; -use reth_primitives::Address; +use alloy_primitives::Address; use tracing::error; use crate::primitives::OrderId; @@ -102,8 +102,8 @@ mod test { use super::MultiShareBundleMerger; + use alloy_primitives::Address; use lazy_static::lazy_static; - use reth_primitives::Address; lazy_static! { static ref SIGNER_1: Address = Address::random(); static ref SIGNER_2: Address = Address::random(); diff --git a/crates/rbuilder/src/building/block_orders/test_context.rs b/crates/rbuilder/src/building/block_orders/test_context.rs index fc21bac4..02e00d48 100644 --- a/crates/rbuilder/src/building/block_orders/test_context.rs +++ b/crates/rbuilder/src/building/block_orders/test_context.rs @@ -1,6 +1,6 @@ use std::{cell::RefCell, rc::Rc}; -use reth_primitives::{Address, B256, U256}; +use alloy_primitives::{Address, B256, U256}; use crate::{ primitives::{ diff --git a/crates/rbuilder/src/building/builders/block_building_helper.rs b/crates/rbuilder/src/building/builders/block_building_helper.rs index 2b100f0b..5f5fbbb7 100644 --- a/crates/rbuilder/src/building/builders/block_building_helper.rs +++ b/crates/rbuilder/src/building/builders/block_building_helper.rs @@ -4,12 +4,10 @@ use std::{ time::{Duration, Instant}, }; -use alloy_primitives::U256; -use reth::tasks::pool::BlockingTaskPool; +use alloy_primitives::{utils::format_ether, U256}; +use reth::revm::cached::CachedReads; use reth_db::Database; -use reth_payload_builder::database::CachedReads; -use reth_primitives::format_ether; -use reth_provider::{DatabaseProviderFactory, StateProviderFactory}; +use reth_provider::{BlockReader, DatabaseProviderFactory, StateProviderFactory}; use time::OffsetDateTime; use tokio_util::sync::CancellationToken; use tracing::{debug, error, trace}; @@ -85,7 +83,10 @@ pub trait BlockBuildingHelper: Send + Sync { pub struct BlockBuildingHelperFromProvider where DB: Database + Clone + 'static, - P: DatabaseProviderFactory + StateProviderFactory + Clone + 'static, + P: DatabaseProviderFactory + + StateProviderFactory + + Clone + + 'static, { /// Balance of fee recipient before we stared building. _fee_recipient_balance_start: U256, @@ -102,7 +103,6 @@ where built_block_trace: BuiltBlockTrace, /// Needed to get the initial state and the final root hash calculation. provider: P, - root_hash_task_pool: BlockingTaskPool, root_hash_config: RootHashConfig, /// Token to cancel in case of fatal error (if we believe that it's impossible to build for this block). cancel_on_fatal_error: CancellationToken, @@ -151,7 +151,10 @@ pub struct FinalizeBlockResult { impl BlockBuildingHelperFromProvider where DB: Database + Clone + 'static, - P: DatabaseProviderFactory + StateProviderFactory + Clone + 'static, + P: DatabaseProviderFactory + + StateProviderFactory + + Clone + + 'static, { /// allow_tx_skip: see [`PartialBlockFork`] /// Performs initialization: @@ -161,7 +164,6 @@ where #[allow(clippy::too_many_arguments)] pub fn new( provider: P, - root_hash_task_pool: BlockingTaskPool, root_hash_config: RootHashConfig, building_ctx: BlockBuildingContext, cached_reads: Option, @@ -203,7 +205,6 @@ where building_ctx, built_block_trace: BuiltBlockTrace::new(), provider, - root_hash_task_pool, root_hash_config, cancel_on_fatal_error, phantom: PhantomData, @@ -218,7 +219,7 @@ where built_block_trace: &BuiltBlockTrace, sim_gas_used: u64, ) { - let txs = finalized_block.sealed_block.body.len(); + let txs = finalized_block.sealed_block.body.transactions.len(); let gas_used = finalized_block.sealed_block.gas_used; let blobs = finalized_block.txs_blob_sidecars.len(); @@ -290,7 +291,10 @@ where impl BlockBuildingHelper for BlockBuildingHelperFromProvider where DB: Database + Clone + 'static, - P: DatabaseProviderFactory + StateProviderFactory + Clone + 'static, + P: DatabaseProviderFactory + + StateProviderFactory + + Clone + + 'static, { /// Forwards to partial_block and updates trace. fn commit_order( @@ -359,7 +363,6 @@ where &self.building_ctx, self.provider.clone(), self.root_hash_config, - self.root_hash_task_pool, ) { Ok(finalized_block) => finalized_block, Err(err) => { @@ -392,6 +395,7 @@ where sealed_block: finalized_block.sealed_block, txs_blobs_sidecars: finalized_block.txs_blob_sidecars, builder_name: self.builder_name.clone(), + execution_requests: finalized_block.execution_requests, }; Ok(FinalizeBlockResult { block, diff --git a/crates/rbuilder/src/building/builders/mock_block_building_helper.rs b/crates/rbuilder/src/building/builders/mock_block_building_helper.rs index 3850a391..f55f1889 100644 --- a/crates/rbuilder/src/building/builders/mock_block_building_helper.rs +++ b/crates/rbuilder/src/building/builders/mock_block_building_helper.rs @@ -6,7 +6,7 @@ use crate::{ primitives::SimulatedOrder, }; use alloy_primitives::U256; -use reth_payload_builder::database::CachedReads; +use reth::revm::cached::CachedReads; use reth_primitives::SealedBlock; use time::OffsetDateTime; @@ -81,6 +81,7 @@ impl BlockBuildingHelper for MockBlockBuildingHelper { sealed_block: SealedBlock::default(), txs_blobs_sidecars: Vec::new(), builder_name: "BlockBuildingHelper".to_string(), + execution_requests: Default::default(), }; Ok(FinalizeBlockResult { diff --git a/crates/rbuilder/src/building/builders/mod.rs b/crates/rbuilder/src/building/builders/mod.rs index 8232efbc..f25e5353 100644 --- a/crates/rbuilder/src/building/builders/mod.rs +++ b/crates/rbuilder/src/building/builders/mod.rs @@ -12,14 +12,13 @@ use crate::{ utils::{is_provider_factory_health_error, NonceCache}, }; use ahash::HashSet; -use alloy_primitives::{Address, B256}; +use alloy_primitives::{Address, Bytes, B256}; use block_building_helper::BlockBuildingHelper; use reth::{ primitives::{BlobTransactionSidecar, SealedBlock}, - tasks::pool::BlockingTaskPool, + revm::cached::CachedReads, }; use reth_db::Database; -use reth_payload_builder::database::CachedReads; use reth_provider::{DatabaseProviderFactory, StateProviderFactory}; use std::{fmt::Debug, marker::PhantomData, sync::Arc}; use tokio::sync::{broadcast, broadcast::error::TryRecvError}; @@ -33,6 +32,8 @@ pub struct Block { pub sealed_block: SealedBlock, /// Sidecars for the txs included in SealedBlock pub txs_blobs_sidecars: Vec>, + /// The Pectra execution requests for this bid. + pub execution_requests: Vec, pub builder_name: String, } @@ -40,7 +41,6 @@ pub struct Block { pub struct LiveBuilderInput { pub provider: P, pub root_hash_config: RootHashConfig, - pub root_hash_task_pool: BlockingTaskPool, pub ctx: BlockBuildingContext, pub input: broadcast::Receiver, pub sink: Arc, @@ -215,7 +215,7 @@ pub struct BlockBuildingAlgorithmInput

{ pub trait BlockBuildingAlgorithm: Debug + Send + Sync where DB: Database + Clone + 'static, - P: DatabaseProviderFactory + StateProviderFactory + Clone + 'static, + P: DatabaseProviderFactory + StateProviderFactory + Clone + 'static, { fn name(&self) -> String; fn build_blocks(&self, input: BlockBuildingAlgorithmInput

); diff --git a/crates/rbuilder/src/building/builders/ordering_builder.rs b/crates/rbuilder/src/building/builders/ordering_builder.rs index 55e392c8..6c233595 100644 --- a/crates/rbuilder/src/building/builders/ordering_builder.rs +++ b/crates/rbuilder/src/building/builders/ordering_builder.rs @@ -18,10 +18,9 @@ use crate::{ }; use ahash::{HashMap, HashSet}; use alloy_primitives::Address; -use reth::tasks::pool::BlockingTaskPool; +use reth::revm::cached::CachedReads; use reth_db::database::Database; -use reth_payload_builder::database::CachedReads; -use reth_provider::{DatabaseProviderFactory, StateProviderFactory}; +use reth_provider::{BlockReader, DatabaseProviderFactory, StateProviderFactory}; use serde::Deserialize; use std::{ marker::PhantomData, @@ -66,7 +65,10 @@ impl OrderingBuilderConfig { pub fn run_ordering_builder(input: LiveBuilderInput, config: &OrderingBuilderConfig) where DB: Database + Clone + 'static, - P: DatabaseProviderFactory + StateProviderFactory + Clone + 'static, + P: DatabaseProviderFactory + + StateProviderFactory + + Clone + + 'static, { let mut order_intake_consumer = OrderIntakeConsumer::new( input.provider.clone(), @@ -78,7 +80,6 @@ where let mut builder = OrderingBuilderContext::new( input.provider.clone(), - input.root_hash_task_pool, input.builder_name, input.ctx, config.clone(), @@ -137,7 +138,10 @@ pub fn backtest_simulate_block( ) -> eyre::Result<(Block, CachedReads)> where DB: Database + Clone + 'static, - P: DatabaseProviderFactory + StateProviderFactory + Clone + 'static, + P: DatabaseProviderFactory + + StateProviderFactory + + Clone + + 'static, { let use_suggested_fee_recipient_as_coinbase = ordering_config.coinbase_payment; let state_provider = input @@ -151,7 +155,6 @@ where )?; let mut builder = OrderingBuilderContext::new( input.provider.clone(), - BlockingTaskPool::build()?, input.builder_name, input.ctx.clone(), ordering_config, @@ -179,7 +182,6 @@ where #[derive(Debug)] pub struct OrderingBuilderContext { provider: P, - root_hash_task_pool: BlockingTaskPool, builder_name: String, ctx: BlockBuildingContext, config: OrderingBuilderConfig, @@ -198,11 +200,13 @@ pub struct OrderingBuilderContext { impl OrderingBuilderContext where DB: Database + Clone + 'static, - P: DatabaseProviderFactory + StateProviderFactory + Clone + 'static, + P: DatabaseProviderFactory + + StateProviderFactory + + Clone + + 'static, { pub fn new( provider: P, - root_hash_task_pool: BlockingTaskPool, builder_name: String, ctx: BlockBuildingContext, config: OrderingBuilderConfig, @@ -210,7 +214,6 @@ where ) -> Self { Self { provider, - root_hash_task_pool, builder_name, ctx, config, @@ -258,7 +261,6 @@ where let mut block_building_helper = BlockBuildingHelperFromProvider::new( self.provider.clone(), - self.root_hash_task_pool.clone(), self.root_hash_config.clone(), new_ctx, self.cached_reads.take(), @@ -344,7 +346,6 @@ where #[derive(Debug)] pub struct OrderingBuildingAlgorithm { root_hash_config: RootHashConfig, - root_hash_task_pool: BlockingTaskPool, sbundle_mergeabe_signers: Vec

, config: OrderingBuilderConfig, name: String, @@ -353,14 +354,12 @@ pub struct OrderingBuildingAlgorithm { impl OrderingBuildingAlgorithm { pub fn new( root_hash_config: RootHashConfig, - root_hash_task_pool: BlockingTaskPool, sbundle_mergeabe_signers: Vec
, config: OrderingBuilderConfig, name: String, ) -> Self { Self { root_hash_config, - root_hash_task_pool, sbundle_mergeabe_signers, config, name, @@ -371,7 +370,10 @@ impl OrderingBuildingAlgorithm { impl BlockBuildingAlgorithm for OrderingBuildingAlgorithm where DB: Database + Clone + 'static, - P: DatabaseProviderFactory + StateProviderFactory + Clone + 'static, + P: DatabaseProviderFactory + + StateProviderFactory + + Clone + + 'static, { fn name(&self) -> String { self.name.clone() @@ -381,7 +383,6 @@ where let live_input = LiveBuilderInput { provider: input.provider, root_hash_config: self.root_hash_config.clone(), - root_hash_task_pool: self.root_hash_task_pool.clone(), ctx: input.ctx.clone(), input: input.input, sink: input.sink, diff --git a/crates/rbuilder/src/building/builders/parallel_builder/block_building_result_assembler.rs b/crates/rbuilder/src/building/builders/parallel_builder/block_building_result_assembler.rs index 0728824e..37b95347 100644 --- a/crates/rbuilder/src/building/builders/parallel_builder/block_building_result_assembler.rs +++ b/crates/rbuilder/src/building/builders/parallel_builder/block_building_result_assembler.rs @@ -4,10 +4,9 @@ use super::{ }; use ahash::HashMap; use alloy_primitives::utils::format_ether; -use reth::tasks::pool::BlockingTaskPool; +use reth::revm::cached::CachedReads; use reth_db::Database; -use reth_payload_builder::database::CachedReads; -use reth_provider::{DatabaseProviderFactory, StateProviderFactory}; +use reth_provider::{BlockReader, DatabaseProviderFactory, StateProviderFactory}; use std::{marker::PhantomData, sync::Arc, time::Instant}; use time::OffsetDateTime; use tokio_util::sync::CancellationToken; @@ -27,7 +26,6 @@ use crate::{ /// Assembles block building results from the best orderings of order groups. pub struct BlockBuildingResultAssembler { provider: P, - root_hash_task_pool: BlockingTaskPool, ctx: BlockBuildingContext, cancellation_token: CancellationToken, cached_reads: Option, @@ -46,7 +44,10 @@ pub struct BlockBuildingResultAssembler { impl BlockBuildingResultAssembler where DB: Database + Clone + 'static, - P: DatabaseProviderFactory + StateProviderFactory + Clone + 'static, + P: DatabaseProviderFactory + + StateProviderFactory + + Clone + + 'static, { /// Creates a new `BlockBuildingResultAssembler`. /// @@ -62,7 +63,6 @@ where root_hash_config: RootHashConfig, best_results: Arc, provider: P, - root_hash_task_pool: BlockingTaskPool, ctx: BlockBuildingContext, cancellation_token: CancellationToken, builder_name: String, @@ -71,7 +71,6 @@ where ) -> Self { Self { provider, - root_hash_task_pool, ctx, cancellation_token, cached_reads: None, @@ -200,7 +199,6 @@ where let mut block_building_helper = BlockBuildingHelperFromProvider::new( self.provider.clone(), - self.root_hash_task_pool.clone(), self.root_hash_config.clone(), ctx, self.cached_reads.clone(), @@ -269,7 +267,6 @@ where ) -> eyre::Result> { let mut block_building_helper = BlockBuildingHelperFromProvider::new( self.provider.clone(), - self.root_hash_task_pool.clone(), self.root_hash_config.clone(), // Adjust as needed for backtest self.ctx.clone(), None, // No cached reads for backtest start diff --git a/crates/rbuilder/src/building/builders/parallel_builder/conflict_resolvers.rs b/crates/rbuilder/src/building/builders/parallel_builder/conflict_resolvers.rs index 6403752d..1dccc101 100644 --- a/crates/rbuilder/src/building/builders/parallel_builder/conflict_resolvers.rs +++ b/crates/rbuilder/src/building/builders/parallel_builder/conflict_resolvers.rs @@ -3,8 +3,7 @@ use alloy_primitives::{Address, U256}; use eyre::Result; use itertools::Itertools; use rand::{seq::SliceRandom, SeedableRng}; -use reth::providers::StateProvider; -use reth_payload_builder::database::CachedReads; +use reth::{providers::StateProvider, revm::cached::CachedReads}; use reth_provider::StateProviderFactory; use std::sync::Arc; use tokio_util::sync::CancellationToken; @@ -465,12 +464,10 @@ mod tests { use std::time::Instant; use ahash::HashSet; - use uuid::Uuid; - + use alloy_consensus::TxLegacy; use alloy_primitives::{Address, TxHash, B256, U256}; - use reth::primitives::{ - Transaction, TransactionSigned, TransactionSignedEcRecovered, TxLegacy, - }; + use reth::primitives::{Transaction, TransactionSigned, TransactionSignedEcRecovered}; + use uuid::Uuid; use super::*; use crate::{ diff --git a/crates/rbuilder/src/building/builders/parallel_builder/conflict_task_generator.rs b/crates/rbuilder/src/building/builders/parallel_builder/conflict_task_generator.rs index ee1931ae..9750dc80 100644 --- a/crates/rbuilder/src/building/builders/parallel_builder/conflict_task_generator.rs +++ b/crates/rbuilder/src/building/builders/parallel_builder/conflict_task_generator.rs @@ -404,12 +404,10 @@ mod tests { use crate::primitives::{ MempoolTx, Order, SimValue, SimulatedOrder, TransactionSignedEcRecoveredWithBlobs, }; - use std::sync::Arc; - + use alloy_consensus::TxLegacy; use alloy_primitives::{Address, TxHash, B256, U256}; - use reth::primitives::{ - Transaction, TransactionSigned, TransactionSignedEcRecovered, TxLegacy, - }; + use reth::primitives::{Transaction, TransactionSigned, TransactionSignedEcRecovered}; + use std::sync::Arc; use crate::building::evm_inspector::{SlotKey, UsedStateTrace}; use std::sync::mpsc; diff --git a/crates/rbuilder/src/building/builders/parallel_builder/groups.rs b/crates/rbuilder/src/building/builders/parallel_builder/groups.rs index 72518e82..2e742341 100644 --- a/crates/rbuilder/src/building/builders/parallel_builder/groups.rs +++ b/crates/rbuilder/src/building/builders/parallel_builder/groups.rs @@ -234,10 +234,9 @@ impl Default for ConflictFinder { #[cfg(test)] mod tests { + use alloy_consensus::TxLegacy; use alloy_primitives::{Address, TxHash, B256, U256}; - use reth::primitives::{ - Transaction, TransactionSigned, TransactionSignedEcRecovered, TxLegacy, - }; + use reth::primitives::{Transaction, TransactionSigned, TransactionSignedEcRecovered}; use crate::{ building::evm_inspector::{SlotKey, UsedStateTrace}, diff --git a/crates/rbuilder/src/building/builders/parallel_builder/mod.rs b/crates/rbuilder/src/building/builders/parallel_builder/mod.rs index e70e682c..4b715b1f 100644 --- a/crates/rbuilder/src/building/builders/parallel_builder/mod.rs +++ b/crates/rbuilder/src/building/builders/parallel_builder/mod.rs @@ -36,10 +36,9 @@ use crate::{ roothash::RootHashConfig, }; use alloy_primitives::Address; -use reth::tasks::pool::BlockingTaskPool; +use reth::revm::cached::CachedReads; use reth_db::database::Database; -use reth_payload_builder::database::CachedReads; -use reth_provider::{DatabaseProviderFactory, StateProviderFactory}; +use reth_provider::{BlockReader, DatabaseProviderFactory, StateProviderFactory}; use self::{ block_building_result_assembler::BlockBuildingResultAssembler, @@ -86,7 +85,10 @@ struct ParallelBuilder { impl ParallelBuilder where DB: Database + Clone + 'static, - P: DatabaseProviderFactory + StateProviderFactory + Clone + 'static, + P: DatabaseProviderFactory + + StateProviderFactory + + Clone + + 'static, { /// Creates a ParallelBuilder. /// Sets up the various components and communication channels. @@ -123,7 +125,6 @@ where input.root_hash_config, Arc::clone(&best_results), input.provider.clone(), - input.root_hash_task_pool.clone(), input.ctx.clone(), input.cancel.clone(), input.builder_name.clone(), @@ -185,7 +186,10 @@ where pub fn run_parallel_builder(input: LiveBuilderInput, config: &ParallelBuilderConfig) where DB: Database + Clone + 'static, - P: DatabaseProviderFactory + StateProviderFactory + Clone + 'static, + P: DatabaseProviderFactory + + StateProviderFactory + + Clone + + 'static, { let cancel_for_results_aggregator = input.cancel.clone(); let cancel_for_block_building_result_assembler = input.cancel.clone(); @@ -272,7 +276,10 @@ pub fn parallel_build_backtest( ) -> Result<(Block, CachedReads)> where DB: Database + Clone + 'static, - P: DatabaseProviderFactory + StateProviderFactory + Clone + 'static, + P: DatabaseProviderFactory + + StateProviderFactory + + Clone + + 'static, { let start_time = Instant::now(); @@ -327,7 +334,6 @@ where RootHashConfig::skip_root_hash(), Arc::clone(&best_results), input.provider.clone(), - BlockingTaskPool::build()?, input.ctx.clone(), CancellationToken::new(), String::from("backtest_builder"), @@ -378,7 +384,6 @@ where #[derive(Debug)] pub struct ParallelBuildingAlgorithm { root_hash_config: RootHashConfig, - root_hash_task_pool: BlockingTaskPool, sbundle_mergeabe_signers: Vec
, config: ParallelBuilderConfig, name: String, @@ -387,14 +392,12 @@ pub struct ParallelBuildingAlgorithm { impl ParallelBuildingAlgorithm { pub fn new( root_hash_config: RootHashConfig, - root_hash_task_pool: BlockingTaskPool, sbundle_mergeabe_signers: Vec
, config: ParallelBuilderConfig, name: String, ) -> Self { Self { root_hash_config, - root_hash_task_pool, sbundle_mergeabe_signers, config, name, @@ -405,7 +408,10 @@ impl ParallelBuildingAlgorithm { impl BlockBuildingAlgorithm for ParallelBuildingAlgorithm where DB: Database + Clone + 'static, - P: DatabaseProviderFactory + StateProviderFactory + Clone + 'static, + P: DatabaseProviderFactory + + StateProviderFactory + + Clone + + 'static, { fn name(&self) -> String { self.name.clone() @@ -415,7 +421,6 @@ where let live_input = LiveBuilderInput { provider: input.provider, root_hash_config: self.root_hash_config.clone(), - root_hash_task_pool: self.root_hash_task_pool.clone(), ctx: input.ctx.clone(), input: input.input, sink: input.sink, diff --git a/crates/rbuilder/src/building/builders/parallel_builder/simulation_cache.rs b/crates/rbuilder/src/building/builders/parallel_builder/simulation_cache.rs index bcdd3f22..630c447a 100644 --- a/crates/rbuilder/src/building/builders/parallel_builder/simulation_cache.rs +++ b/crates/rbuilder/src/building/builders/parallel_builder/simulation_cache.rs @@ -2,7 +2,7 @@ use crate::primitives::OrderId; use ahash::HashMap; use alloy_primitives::U256; use parking_lot::RwLock as PLRwLock; -use reth_payload_builder::database::CachedReads; +use reth::revm::cached::CachedReads; use revm::db::BundleState; use std::sync::{ atomic::{AtomicUsize, Ordering}, @@ -189,7 +189,7 @@ mod tests { use reth_primitives::revm_primitives::AccountInfo; use revm::db::{states::StorageSlot, AccountStatus, BundleAccount}; use std::collections::HashMap; - + type AlloyHashMap = HashMap; struct TestDataGenerator { last_used_id: u64, } @@ -208,11 +208,12 @@ mod tests { fn create_cached_simulation_state(&mut self) -> CachedSimulationState { let mut cached_reads = CachedReads::default(); - let mut storage = HashMap::new(); + let mut storage = AlloyHashMap::default(); storage.insert(U256::from(self.last_used_id), U256::from(self.last_used_id)); cached_reads.insert_account(Address::random(), AccountInfo::default(), storage); - let mut storage_bundle_account: HashMap = HashMap::new(); + let mut storage_bundle_account: AlloyHashMap = + AlloyHashMap::default(); let storage_slot = StorageSlot::new_changed( U256::from(self.last_used_id), U256::from(self.last_used_id + 1), diff --git a/crates/rbuilder/src/building/conflict.rs b/crates/rbuilder/src/building/conflict.rs index a0c784cd..f5fad782 100644 --- a/crates/rbuilder/src/building/conflict.rs +++ b/crates/rbuilder/src/building/conflict.rs @@ -1,7 +1,8 @@ use super::{BlockBuildingContext, BlockState, PartialBlockFork}; use crate::primitives::{Order, OrderId}; +use alloy_primitives::Address; use itertools::Itertools; -use reth::{primitives::Address, providers::StateProviderBox}; +use reth::providers::StateProviderBox; use reth_provider::StateProvider; use revm_primitives::U256; use std::{ diff --git a/crates/rbuilder/src/building/evm_inspector.rs b/crates/rbuilder/src/building/evm_inspector.rs index 073c5889..79a47473 100644 --- a/crates/rbuilder/src/building/evm_inspector.rs +++ b/crates/rbuilder/src/building/evm_inspector.rs @@ -1,4 +1,5 @@ use ahash::HashMap; +use alloy_consensus::Transaction; use alloy_primitives::{Address, B256, U256}; use reth_primitives::TransactionSignedEcRecovered; use revm::{ @@ -62,19 +63,19 @@ impl<'a> UsedStateEVMInspector<'a> { address: tx.signer(), key: Default::default(), }, - U256::from(tx.nonce()).into(), + U256::from(tx.as_signed().nonce()).into(), ); self.used_state_trace.written_slot_values.insert( SlotKey { address: tx.signer(), key: Default::default(), }, - U256::from(tx.nonce() + 1).into(), + U256::from(tx.as_signed().nonce() + 1).into(), ); } } -impl<'a, DB> Inspector for UsedStateEVMInspector<'a> +impl Inspector for UsedStateEVMInspector<'_> where DB: Database, { diff --git a/crates/rbuilder/src/building/mod.rs b/crates/rbuilder/src/building/mod.rs index 1b5699ad..7a32d48a 100644 --- a/crates/rbuilder/src/building/mod.rs +++ b/crates/rbuilder/src/building/mod.rs @@ -10,11 +10,13 @@ pub mod payout_tx; pub mod sim; pub mod testing; pub mod tracers; +use alloy_consensus::EMPTY_OMMER_ROOT_HASH; +use alloy_primitives::{Address, Bytes, Sealable, U256}; pub use block_orders::BlockOrders; use eth_sparse_mpt::SparseTrieSharedCache; use reth_db::Database; -use reth_primitives::proofs::calculate_requests_root; -use reth_provider::{DatabaseProviderFactory, StateProviderFactory}; +use reth_primitives::BlockBody; +use reth_provider::{BlockReader, DatabaseProviderFactory, StateProviderFactory}; use crate::{ primitives::{Order, OrderId, SimValue, SimulatedOrder, TransactionSignedEcRecoveredWithBlobs}, @@ -22,30 +24,27 @@ use crate::{ utils::{a2r_withdrawal, calc_gas_limit, timestamp_as_u64, Signer}, }; use ahash::HashSet; +use alloy_eips::{calc_excess_blob_gas, eip7685::Requests, merge::BEACON_NONCE}; +use alloy_rpc_types_beacon::events::PayloadAttributesEvent; use jsonrpsee::core::Serialize; use reth::{ payload::PayloadId, primitives::{ - constants::BEACON_NONCE, eip4844::calculate_excess_blob_gas, proofs, - revm_primitives::InvalidTransaction, Address, BlobTransactionSidecar, Block, Head, Header, - Receipt, Receipts, SealedBlock, Withdrawals, EMPTY_OMMER_ROOT_HASH, U256, + proofs, revm_primitives::InvalidTransaction, BlobTransactionSidecar, Block, Head, Header, + Receipt, Receipts, SealedBlock, Withdrawals, }, providers::ExecutionOutcome, - rpc::types::beacon::events::PayloadAttributesEvent, - tasks::pool::BlockingTaskPool, + revm::cached::CachedReads, }; use reth_basic_payload_builder::{commit_withdrawals, WithdrawalsOutcome}; use reth_chainspec::{ChainSpec, EthereumHardforks}; use reth_errors::ProviderError; -use reth_evm::system_calls::{ - post_block_consolidation_requests_contract_call, post_block_withdrawal_requests_contract_call, - pre_block_beacon_root_contract_call, pre_block_blockhashes_contract_call, -}; +use reth_evm::{system_calls::SystemCaller, ConfigureEvmEnv, NextBlockEnvAttributes}; use reth_evm_ethereum::{eip6110::parse_deposits_from_receipts, revm_spec, EthEvmConfig}; -use reth_node_api::PayloadBuilderAttributes; -use reth_payload_builder::{database::CachedReads, EthPayloadBuilderAttributes}; +use reth_node_api::{EngineApiMessageVersion, PayloadBuilderAttributes}; +use reth_payload_builder::EthPayloadBuilderAttributes; use revm::{ - db::states::bundle_state::BundleRetention::{self, PlainState}, + db::states::bundle_state::BundleRetention, primitives::{BlobExcessGasAndPrice, BlockEnv, CfgEnvWithHandlerCfg, SpecId}, }; use serde::Deserialize; @@ -91,6 +90,7 @@ pub struct BlockBuildingContext { impl BlockBuildingContext { #[allow(clippy::too_many_arguments)] /// spec_id None: we use the proper SpecId for the block timestamp. + /// We are forced to return Option since next_cfg_and_block_env returns Result although it never fails! (reth v1.1.1) pub fn from_attributes( attributes: PayloadAttributesEvent, parent: &Header, @@ -100,13 +100,24 @@ impl BlockBuildingContext { prefer_gas_limit: Option, extra_data: Vec, spec_id: Option, - ) -> BlockBuildingContext { + ) -> Option { let attributes = EthPayloadBuilderAttributes::try_new( attributes.data.parent_block_hash, attributes.data.payload_attributes.clone(), + EngineApiMessageVersion::default() as u8, ) .expect("PayloadBuilderAttributes::try_new"); - let (initialized_cfg, mut block_env) = attributes.cfg_and_block_env(&chain_spec, parent); + let eth_evm_config = EthEvmConfig::new(chain_spec.clone()); + let (initialized_cfg, mut block_env) = eth_evm_config + .next_cfg_and_block_env( + parent, + NextBlockEnvAttributes { + timestamp: attributes.timestamp(), + suggested_fee_recipient: attributes.suggested_fee_recipient(), + prev_randao: attributes.prev_randao(), + }, + ) + .ok()?; block_env.coinbase = signer.address; if let Some(desired_limit) = prefer_gas_limit { block_env.gas_limit = @@ -117,14 +128,14 @@ impl BlockBuildingContext { if chain_spec.is_cancun_active_at_timestamp(parent.timestamp) { let parent_excess_blob_gas = parent.excess_blob_gas.unwrap_or_default(); let parent_blob_gas_used = parent.blob_gas_used.unwrap_or_default(); - Some(calculate_excess_blob_gas( + Some(calc_excess_blob_gas( parent_excess_blob_gas, parent_blob_gas_used, )) } else { // for the first post-fork block, both parent.blob_gas_used and // parent.excess_blob_gas are evaluated as 0 - Some(calculate_excess_blob_gas(0, 0)) + Some(calc_excess_blob_gas(0, 0)) } } else { None @@ -141,7 +152,7 @@ impl BlockBuildingContext { ); revm_spec(&chain_spec, &head) }); - BlockBuildingContext { + Some(BlockBuildingContext { block_env, initialized_cfg, attributes, @@ -152,7 +163,7 @@ impl BlockBuildingContext { excess_blob_gas, spec_id, shared_sparse_mpt_cache: Default::default(), - } + }) } /// `from_block_data` is used to create `BlockBuildingContext` from onchain block for backtest purposes @@ -172,7 +183,7 @@ impl BlockBuildingContext { let blob_excess_gas_and_price = if chain_spec.is_cancun_active_at_timestamp(onchain_block.header.timestamp) { Some(BlobExcessGasAndPrice::new( - onchain_block.header.excess_blob_gas.unwrap_or_default() as u64, + onchain_block.header.excess_blob_gas.unwrap_or_default(), )) } else { None @@ -234,7 +245,7 @@ impl BlockBuildingContext { builder_signer, blocklist, extra_data: Vec::new(), - excess_blob_gas: onchain_block.header.excess_blob_gas.map(|b| b as u64), + excess_blob_gas: onchain_block.header.excess_blob_gas, spec_id, shared_sparse_mpt_cache: Default::default(), } @@ -414,6 +425,9 @@ pub struct FinalizeResult { pub cached_reads: CachedReads, // sidecars for all txs in SealedBlock pub txs_blob_sidecars: Vec>, + /// The Pectra execution requests for this bid. + pub execution_requests: Vec, + pub root_hash_time: Duration, } @@ -534,7 +548,7 @@ impl PartialBlock { ) -> Result { self.coinbase_profit .checked_sub(U256::from(gas_limit) * ctx.block_env.basefee) - .ok_or_else(|| InsertPayoutTxErr::ProfitTooLow) + .ok_or(InsertPayoutTxErr::ProfitTooLow) } /// Inserts payout tx to ctx.attributes.suggested_fee_recipient (should be called at the end of the block) @@ -580,6 +594,7 @@ impl PartialBlock { Ok(()) } + /// Mostly based on reth's (v1.1.1) default_ethereum_payload_builder. #[allow(clippy::too_many_arguments)] pub fn finalize( self, @@ -587,12 +602,51 @@ impl PartialBlock { ctx: &BlockBuildingContext, provider: P, root_hash_config: RootHashConfig, - root_hash_task_pool: BlockingTaskPool, ) -> Result where DB: Database + Clone + 'static, - P: DatabaseProviderFactory + StateProviderFactory + Clone + 'static, + P: DatabaseProviderFactory + + StateProviderFactory + + Clone + + 'static, { + let requests = if ctx + .chain_spec + .is_prague_active_at_timestamp(ctx.attributes.timestamp()) + { + let mut system_caller = SystemCaller::new( + EthEvmConfig::new(ctx.chain_spec.clone()), + ctx.chain_spec.clone(), + ); + let mut db = state.new_db_ref(); + + let deposit_requests = + parse_deposits_from_receipts(&ctx.chain_spec, self.receipts.iter()) + .map_err(|err| FinalizeError::Other(err.into()))?; + let withdrawal_requests = system_caller + .post_block_withdrawal_requests_contract_call( + db.as_mut(), + &ctx.initialized_cfg, + &ctx.block_env, + ) + .map_err(|err| FinalizeError::Other(err.into()))?; + let consolidation_requests = system_caller + .post_block_consolidation_requests_contract_call( + db.as_mut(), + &ctx.initialized_cfg, + &ctx.block_env, + ) + .map_err(|err| FinalizeError::Other(err.into()))?; + + Some(Requests::new(vec![ + deposit_requests, + withdrawal_requests, + consolidation_requests, + ])) + } else { + None + }; + let (withdrawals_root, withdrawals) = { let mut db = state.new_db_ref(); let WithdrawalsOutcome { @@ -605,48 +659,16 @@ impl PartialBlock { ctx.attributes.withdrawals.clone(), ) .map_err(|err| FinalizeError::Other(err.into()))?; - db.as_mut().merge_transitions(PlainState); + // merge all transitions into bundle state, this would apply the withdrawal balance changes + // and 4788 contract call + db.as_mut().merge_transitions(BundleRetention::Reverts); (withdrawals_root, withdrawals) }; - let (requests, requests_root) = if ctx - .chain_spec - .is_prague_active_at_timestamp(ctx.attributes.timestamp()) - { - let evm_config = EthEvmConfig::default(); - let mut db = state.new_db_ref(); - - let deposit_requests = - parse_deposits_from_receipts(&ctx.chain_spec, self.receipts.iter()) - .map_err(|err| FinalizeError::Other(err.into()))?; - let withdrawal_requests = post_block_withdrawal_requests_contract_call( - &evm_config, - db.as_mut(), - &ctx.initialized_cfg, - &ctx.block_env, - ) - .map_err(|err| FinalizeError::Other(err.into()))?; - let consolidation_requests = post_block_consolidation_requests_contract_call( - &evm_config, - db.as_mut(), - &ctx.initialized_cfg, - &ctx.block_env, - ) - .map_err(|err| FinalizeError::Other(err.into()))?; - - let requests = [ - deposit_requests, - withdrawal_requests, - consolidation_requests, - ] - .concat(); - let requests_root = calculate_requests_root(&requests); - (Some(requests.into()), Some(requests_root)) - } else { - (None, None) - }; - let (cached_reads, bundle) = state.clone_bundle_and_cache(); + let block_number = ctx.block_env.number.to::(); + + let requests_hash = requests.as_ref().map(|requests| requests.requests_hash()); let execution_outcome = ExecutionOutcome::new( bundle, Receipts::from(vec![self @@ -654,10 +676,9 @@ impl PartialBlock { .into_iter() .map(Option::Some) .collect::>()]), - ctx.block_env.number.to::(), + block_number, vec![requests.clone().unwrap_or_default()], ); - let block_number = ctx.block_env.number.to::(); let receipts_root = execution_outcome .receipts_root_slow(block_number) @@ -666,12 +687,12 @@ impl PartialBlock { .block_logs_bloom(block_number) .expect("Number is in range"); + // calculate the state root let start = Instant::now(); let state_root = calculate_state_root( provider, ctx.attributes.parent, &execution_outcome, - root_hash_task_pool, ctx.shared_sparse_mpt_cache.clone(), root_hash_config, )?; @@ -720,9 +741,9 @@ impl PartialBlock { logs_bloom, timestamp: ctx.attributes.timestamp, mix_hash: ctx.attributes.prev_randao, - nonce: BEACON_NONCE, + nonce: BEACON_NONCE.into(), base_fee_per_gas: Some(ctx.block_env.basefee.to()), - number: ctx.block_env.number.to::(), + number: block_number, gas_limit: ctx.block_env.gas_limit.to(), difficulty: U256::ZERO, gas_used: self.gas_used, @@ -730,19 +751,21 @@ impl PartialBlock { parent_beacon_block_root: ctx.attributes.parent_beacon_block_root, blob_gas_used, excess_blob_gas, - requests_root, + requests_hash, }; + // seal the block let block = Block { header, - body: self - .executed_tx - .into_iter() - .map(|t| t.into_internal_tx_unsecure().into()) - .collect(), - ommers: vec![], - withdrawals, - requests, + body: BlockBody { + transactions: self + .executed_tx + .into_iter() + .map(|t| t.into_internal_tx_unsecure().into()) + .collect(), + ommers: vec![], + withdrawals, + }, }; Ok(FinalizeResult { @@ -750,6 +773,7 @@ impl PartialBlock { cached_reads, txs_blob_sidecars, root_hash_time, + execution_requests: requests.map(|er| er.take()).unwrap_or_default(), }) } @@ -758,20 +782,19 @@ impl PartialBlock { ctx: &BlockBuildingContext, state: &mut BlockState, ) -> eyre::Result<()> { - let evm_config = EthEvmConfig::default(); let mut db = state.new_db_ref(); - pre_block_beacon_root_contract_call( + let mut system_caller = SystemCaller::new( + EthEvmConfig::new(ctx.chain_spec.clone()), + ctx.chain_spec.clone(), + ); + system_caller.pre_block_beacon_root_contract_call( db.as_mut(), - &evm_config, - &ctx.chain_spec, &ctx.initialized_cfg, &ctx.block_env, ctx.attributes.parent_beacon_block_root(), )?; - pre_block_blockhashes_contract_call( + system_caller.pre_block_blockhashes_contract_call( db.as_mut(), - &evm_config, - &ctx.chain_spec, &ctx.initialized_cfg, &ctx.block_env, ctx.attributes.parent, diff --git a/crates/rbuilder/src/building/order_commit.rs b/crates/rbuilder/src/building/order_commit.rs index f82e5a56..4f7855a4 100644 --- a/crates/rbuilder/src/building/order_commit.rs +++ b/crates/rbuilder/src/building/order_commit.rs @@ -12,14 +12,11 @@ use crate::{ use alloy_primitives::{Address, B256, U256}; -use reth::revm::database::StateProviderDatabase; +use alloy_consensus::{constants::KECCAK_EMPTY, Transaction}; +use alloy_eips::eip4844::{DATA_GAS_PER_BLOB, MAX_DATA_GAS_PER_BLOCK}; +use reth::revm::{cached::CachedReads, database::StateProviderDatabase}; use reth_errors::ProviderError; -use reth_payload_builder::database::CachedReads; -use reth_primitives::{ - constants::eip4844::{DATA_GAS_PER_BLOB, MAX_DATA_GAS_PER_BLOCK}, - transaction::FillTxEnv, - Receipt, KECCAK_EMPTY, -}; +use reth_primitives::{transaction::FillTxEnv, Receipt}; use reth_provider::{StateProvider, StateProviderBox}; use revm::{ db::{states::bundle_state::BundleRetention, BundleState}, @@ -150,7 +147,7 @@ where } } -impl<'a, DB> Drop for BlockStateDBRef<'a, DB> +impl Drop for BlockStateDBRef<'_, DB> where DB: Database, { @@ -159,7 +156,7 @@ where } } -impl<'a, DB> AsRef> for BlockStateDBRef<'a, DB> +impl AsRef> for BlockStateDBRef<'_, DB> where DB: Database, { @@ -168,7 +165,7 @@ where } } -impl<'a, DB> AsMut> for BlockStateDBRef<'a, DB> +impl AsMut> for BlockStateDBRef<'_, DB> where DB: Database, { @@ -412,7 +409,7 @@ impl<'a, 'b, Tracer: SimulationTracer> PartialBlockFork<'a, 'b, Tracer> { .checked_sub(U256::from(cumulative_gas_used + gas_reserved)) { Some(gas_left) => { - if tx.gas_limit() > gas_left.to::() { + if tx.as_signed().gas_limit() > gas_left.to::() { return Ok(Err(TransactionErr::GasLeft)); } } @@ -497,7 +494,7 @@ impl<'a, 'b, Tracer: SimulationTracer> PartialBlockFork<'a, 'b, Tracer> { cumulative_blob_gas_used, cumulative_gas_used, tx: tx_with_blobs.clone(), - nonce_updated: (tx.signer(), tx.nonce() + 1), + nonce_updated: (tx.signer(), tx.as_signed().nonce() + 1), receipt, })) } @@ -1120,7 +1117,7 @@ impl<'a, 'b, Tracer: SimulationTracer> PartialBlockFork<'a, 'b, Tracer> { } } -impl<'a, 'b> PartialBlockFork<'a, 'b, ()> { +impl<'a> PartialBlockFork<'a, '_, ()> { pub fn new(state: &'a mut BlockState) -> Self { Self { rollbacks: 0, diff --git a/crates/rbuilder/src/building/payout_tx.rs b/crates/rbuilder/src/building/payout_tx.rs index 3d10a97e..03271c19 100644 --- a/crates/rbuilder/src/building/payout_tx.rs +++ b/crates/rbuilder/src/building/payout_tx.rs @@ -1,13 +1,11 @@ use crate::utils::Signer; use super::{BlockBuildingContext, BlockState}; -use alloy_primitives::{Address, U256}; +use alloy_consensus::{constants::KECCAK_EMPTY, TxEip1559}; +use alloy_primitives::{Address, TxKind as TransactionKind, U256}; use reth_chainspec::ChainSpec; use reth_errors::ProviderError; -use reth_primitives::{ - transaction::FillTxEnv, Transaction, TransactionSignedEcRecovered, TxEip1559, - TxKind as TransactionKind, KECCAK_EMPTY, -}; +use reth_primitives::{transaction::FillTxEnv, Transaction, TransactionSignedEcRecovered}; use revm_primitives::{EVMError, Env, ExecutionResult, TxEnv}; pub fn create_payout_tx( @@ -123,7 +121,7 @@ pub fn estimate_payout_gas_limit( .checked_sub(U256::from(gas_used)) .unwrap_or_default(); let estimation = insert_test_payout_tx(to, ctx, state, gas_left.to())? - .ok_or_else(|| EstimatePayoutGasErr::FailedToEstimate)?; + .ok_or(EstimatePayoutGasErr::FailedToEstimate)?; if insert_test_payout_tx(to, ctx, state, estimation)?.is_some() { return Ok(estimation); diff --git a/crates/rbuilder/src/building/sim.rs b/crates/rbuilder/src/building/sim.rs index 4396e66a..df676dc2 100644 --- a/crates/rbuilder/src/building/sim.rs +++ b/crates/rbuilder/src/building/sim.rs @@ -10,8 +10,8 @@ use crate::{ use ahash::{HashMap, HashSet}; use alloy_primitives::{Address, B256}; use rand::seq::SliceRandom; +use reth::revm::cached::CachedReads; use reth_errors::ProviderError; -use reth_payload_builder::database::CachedReads; use reth_provider::{StateProvider, StateProviderFactory}; use std::{ cmp::{max, min, Ordering}, diff --git a/crates/rbuilder/src/building/testing/bundle_tests/mod.rs b/crates/rbuilder/src/building/testing/bundle_tests/mod.rs index 854ea1a8..6a3bef50 100644 --- a/crates/rbuilder/src/building/testing/bundle_tests/mod.rs +++ b/crates/rbuilder/src/building/testing/bundle_tests/mod.rs @@ -1,8 +1,7 @@ pub mod setup; -use alloy_primitives::{Address, U256}; +use alloy_primitives::{Address, B256, U256}; use itertools::Itertools; -use reth_primitives::B256; use std::collections::HashSet; use uuid::Uuid; diff --git a/crates/rbuilder/src/building/testing/bundle_tests/setup.rs b/crates/rbuilder/src/building/testing/bundle_tests/setup.rs index 67400984..84125a2f 100644 --- a/crates/rbuilder/src/building/testing/bundle_tests/setup.rs +++ b/crates/rbuilder/src/building/testing/bundle_tests/setup.rs @@ -13,7 +13,7 @@ use crate::{ }, }; use alloy_primitives::{Address, TxHash}; -use reth_payload_builder::database::CachedReads; +use reth::revm::cached::CachedReads; use revm::db::BundleState; pub enum NonceValue { diff --git a/crates/rbuilder/src/building/testing/evm_inspector_tests/setup.rs b/crates/rbuilder/src/building/testing/evm_inspector_tests/setup.rs index 2d503dcc..ad0fddd6 100644 --- a/crates/rbuilder/src/building/testing/evm_inspector_tests/setup.rs +++ b/crates/rbuilder/src/building/testing/evm_inspector_tests/setup.rs @@ -1,4 +1,5 @@ -use reth_primitives::{transaction::FillTxEnv, Address, TransactionSignedEcRecovered}; +use alloy_primitives::Address; +use reth_primitives::{transaction::FillTxEnv, TransactionSignedEcRecovered}; use revm::{inspector_handle_register, primitives::Env}; use revm_primitives::TxEnv; diff --git a/crates/rbuilder/src/building/testing/test_chain_state.rs b/crates/rbuilder/src/building/testing/test_chain_state.rs index 50832b8f..b508d4cd 100644 --- a/crates/rbuilder/src/building/testing/test_chain_state.rs +++ b/crates/rbuilder/src/building/testing/test_chain_state.rs @@ -1,23 +1,19 @@ use ahash::HashSet; -use alloy_primitives::{keccak256, utils::parse_ether, Address, BlockHash, Bytes, B256, U256}; +use alloy_consensus::TxEip1559; +use alloy_primitives::{ + keccak256, utils::parse_ether, Address, BlockHash, Bytes, TxKind as TransactionKind, B256, B64, + U256, +}; +use alloy_rpc_types_beacon::events::{PayloadAttributesData, PayloadAttributesEvent}; use lazy_static::lazy_static; use reth::{ - primitives::{ - Account, BlockBody, Bytecode, Header, SealedBlock, TransactionSignedEcRecovered, TxEip1559, - TxKind as TransactionKind, - }, + primitives::{Account, BlockBody, Bytecode, Header, SealedBlock, TransactionSignedEcRecovered}, providers::ProviderFactory, - rpc::types::{ - beacon::events::{PayloadAttributesData, PayloadAttributesEvent}, - engine::PayloadAttributes, - Withdrawal, - }, + rpc::types::{engine::PayloadAttributes, Withdrawal}, }; use reth_chainspec::{ChainSpec, MAINNET}; -use reth_db::{ - cursor::DbCursorRW, tables, test_utils::TempDatabase, transaction::DbTxMut, DatabaseEnv, -}; -use reth_provider::test_utils::create_test_provider_factory; +use reth_db::{cursor::DbCursorRW, tables, transaction::DbTxMut}; +use reth_provider::test_utils::{create_test_provider_factory, MockNodeTypesWithDB}; use revm_primitives::SpecId; use std::sync::Arc; @@ -71,7 +67,7 @@ pub struct TestChainState { dummy_test_address: Address, //NamedAddr::Dummy blocklisted_address: Signer, //NamedAddr::BlockedAddress chain_spec: Arc, - provider_factory: ProviderFactory>>, + provider_factory: ProviderFactory, block_building_context: BlockBuildingContext, } impl TestChainState { @@ -218,7 +214,7 @@ impl TestChainState { &self.block_building_context } - pub fn provider_factory(&self) -> &ProviderFactory>> { + pub fn provider_factory(&self) -> &ProviderFactory { &self.provider_factory } } @@ -305,13 +301,13 @@ impl TestBlockContextBuilder { gas_used: self.parent_gas_used, timestamp: self.parent_timestamp, mix_hash: Default::default(), - nonce: 0, + nonce: B64::ZERO, base_fee_per_gas: Some(self.parent_base_fee_per_gas), blob_gas_used: None, excess_blob_gas: None, parent_beacon_block_root: None, extra_data: Default::default(), - requests_root: Default::default(), + requests_hash: Default::default(), }, self.builder_signer.clone(), self.chain_spec, @@ -319,7 +315,8 @@ impl TestBlockContextBuilder { self.prefer_gas_limit, vec![], Some(SpecId::SHANGHAI), - ); + ) + .unwrap(); if self.use_suggested_fee_recipient_as_coinbase { res.modify_use_suggested_fee_recipient_as_coinbase(); } diff --git a/crates/rbuilder/src/integration/playground.rs b/crates/rbuilder/src/integration/playground.rs index 7d26374b..e9b79c86 100644 --- a/crates/rbuilder/src/integration/playground.rs +++ b/crates/rbuilder/src/integration/playground.rs @@ -4,10 +4,10 @@ use crate::{ }; use alloy_network::EthereumWallet; use alloy_primitives::{address, Address}; +use alloy_rpc_types_beacon::events::PayloadAttributesEvent; use alloy_signer_local::PrivateKeySigner; use futures::StreamExt; use primitive_types::H384; -use reth::rpc::types::beacon::events::PayloadAttributesEvent; use std::{ fs::{File, OpenOptions}, io, diff --git a/crates/rbuilder/src/integration/simple.rs b/crates/rbuilder/src/integration/simple.rs index 17e28492..bcb20792 100644 --- a/crates/rbuilder/src/integration/simple.rs +++ b/crates/rbuilder/src/integration/simple.rs @@ -44,7 +44,7 @@ mod tests { // wait for the transaction in the el node since rbuilder does not implement // the `eth_getTransactionReceipt` method. let binding = ProviderBuilder::new().on_http(Url::parse(srv.el_url()).unwrap()); - let pending_tx = PendingTransactionBuilder::new(&binding, *pending_tx.tx_hash()) + let pending_tx = PendingTransactionBuilder::new(binding, *pending_tx.tx_hash()) .with_timeout(Some(std::time::Duration::from_secs(60))); let receipt = pending_tx.get_receipt().await.unwrap(); diff --git a/crates/rbuilder/src/live_builder/base_config.rs b/crates/rbuilder/src/live_builder/base_config.rs index f6cb7571..a3aed895 100644 --- a/crates/rbuilder/src/live_builder/base_config.rs +++ b/crates/rbuilder/src/live_builder/base_config.rs @@ -12,10 +12,11 @@ use alloy_primitives::{Address, B256}; use eyre::{eyre, Context}; use jsonrpsee::RpcModule; use lazy_static::lazy_static; -use reth::tasks::pool::BlockingTaskPool; +use reth::chainspec::chain_value_parser; use reth_chainspec::ChainSpec; use reth_db::{Database, DatabaseEnv}; -use reth_node_core::args::utils::chain_value_parser; +use reth_node_api::NodeTypesWithDBAdapter; +use reth_node_ethereum::EthereumNode; use reth_primitives::StaticFileSegment; use reth_provider::{ DatabaseProviderFactory, HeaderProvider, StateProviderFactory, StaticFileProviderFactory, @@ -88,7 +89,6 @@ pub struct BaseConfig { pub root_hash_use_sparse_trie: bool, /// compares result of root hash using sparse trie and reference root hash pub root_hash_compare_sparse_trie: bool, - pub root_hash_task_pool_threads: usize, pub watchdog_timeout_sec: u64, @@ -175,7 +175,7 @@ impl BaseConfig { slot_source: SlotSourceType, ) -> eyre::Result< super::LiveBuilder< - ProviderFactoryReopener>, + ProviderFactoryReopener>>, Arc, SlotSourceType, >, @@ -184,7 +184,7 @@ impl BaseConfig { SlotSourceType: SlotSource, { let provider_factory = self.create_provider_factory()?; - self.create_builder_with_provider_factory::>, Arc, SlotSourceType>( + self.create_builder_with_provider_factory::>>, Arc, SlotSourceType>( cancellation_token, sink_factory, slot_source, @@ -203,7 +203,7 @@ impl BaseConfig { ) -> eyre::Result> where DB: Database + Clone + 'static, - P: DatabaseProviderFactory + StateProviderFactory + HeaderProvider + Clone, + P: DatabaseProviderFactory + StateProviderFactory + HeaderProvider + Clone, SlotSourceType: SlotSource, { let order_input_config = OrderInputConfig::from_config(self)?; @@ -262,7 +262,8 @@ impl BaseConfig { /// Open reth db and DB should be opened once per process but it can be cloned and moved to different threads. pub fn create_provider_factory( &self, - ) -> eyre::Result>> { + ) -> eyre::Result>>> + { create_provider_factory( self.reth_datadir.as_deref(), self.reth_db_path.as_deref(), @@ -272,15 +273,6 @@ impl BaseConfig { ) } - /// Creates threadpool for root hash calculation, should be created once per process. - pub fn root_hash_task_pool(&self) -> eyre::Result { - Ok(BlockingTaskPool::new( - BlockingTaskPool::builder() - .num_threads(self.root_hash_task_pool_threads) - .build()?, - )) - } - pub fn live_root_hash_config(&self) -> eyre::Result { if self.root_hash_compare_sparse_trie && !self.root_hash_use_sparse_trie { eyre::bail!( @@ -444,7 +436,6 @@ impl Default for BaseConfig { reth_static_files_path: None, blocklist_file_path: None, extra_data: "extra_data_change_me".to_string(), - root_hash_task_pool_threads: 1, root_hash_use_sparse_trie: false, root_hash_compare_sparse_trie: false, watchdog_timeout_sec: 60 * 3, @@ -469,7 +460,7 @@ pub fn create_provider_factory( reth_static_files_path: Option<&Path>, chain_spec: Arc, rw: bool, -) -> eyre::Result>> { +) -> eyre::Result>>> { // shellexpand the reth datadir let reth_datadir = if let Some(reth_datadir) = reth_datadir { let reth_datadir = reth_datadir @@ -560,13 +551,13 @@ mod test { let data_dir = MaybePlatformPath::::from(tempdir.into_path()); let data_dir = data_dir.unwrap_or_chain_default(Chain::mainnet(), DatadirArgs::default()); - let db = init_db(data_dir.data_dir(), Default::default()).unwrap(); - let provider_factory = ProviderFactory::new( + let db = Arc::new(init_db(data_dir.data_dir(), Default::default()).unwrap()); + let provider_factory = ProviderFactory::>::new( db, SEPOLIA.clone(), StaticFileProvider::read_write(data_dir.static_files().as_path()).unwrap(), ); - init_genesis(provider_factory).unwrap(); + init_genesis(&provider_factory).unwrap(); // Create longer-lived PathBuf values let data_dir_path = data_dir.data_dir(); diff --git a/crates/rbuilder/src/live_builder/block_output/bidding/interfaces.rs b/crates/rbuilder/src/live_builder/block_output/bidding/interfaces.rs index f108161f..a738e7f9 100644 --- a/crates/rbuilder/src/live_builder/block_output/bidding/interfaces.rs +++ b/crates/rbuilder/src/live_builder/block_output/bidding/interfaces.rs @@ -4,9 +4,8 @@ use crate::{ building::builders::{block_building_helper::BlockBuildingHelper, UnfinishedBlockBuildingSink}, live_builder::block_output::bid_value_source::interfaces::BidValueObs, }; -use alloy_primitives::U256; +use alloy_primitives::{BlockNumber, U256}; use mockall::automock; -use reth_primitives::BlockNumber; use time::OffsetDateTime; use tokio_util::sync::CancellationToken; diff --git a/crates/rbuilder/src/live_builder/block_output/bidding/wallet_balance_watcher.rs b/crates/rbuilder/src/live_builder/block_output/bidding/wallet_balance_watcher.rs index cf0aa4e2..7149315c 100644 --- a/crates/rbuilder/src/live_builder/block_output/bidding/wallet_balance_watcher.rs +++ b/crates/rbuilder/src/live_builder/block_output/bidding/wallet_balance_watcher.rs @@ -1,10 +1,7 @@ use std::time::Duration; -use alloy_primitives::{Address, BlockNumber, U256}; -use reth::{ - primitives::format_ether, - providers::{HeaderProvider, ProviderError}, -}; +use alloy_primitives::{utils::format_ether, Address, BlockNumber, U256}; +use reth::providers::{HeaderProvider, ProviderError}; use reth_provider::StateProviderFactory; use time::{error, OffsetDateTime}; use tracing::{error, info}; diff --git a/crates/rbuilder/src/live_builder/block_output/block_sealing_bidder_factory.rs b/crates/rbuilder/src/live_builder/block_output/block_sealing_bidder_factory.rs index b0a89cc1..80f855ce 100644 --- a/crates/rbuilder/src/live_builder/block_output/block_sealing_bidder_factory.rs +++ b/crates/rbuilder/src/live_builder/block_output/block_sealing_bidder_factory.rs @@ -4,8 +4,7 @@ use crate::{ }; use alloy_primitives::U256; use reth_provider::{HeaderProvider, StateProviderFactory}; -use std::fmt::Debug; -use std::sync::Arc; +use std::{fmt::Debug, sync::Arc}; use tracing::error; use super::{ diff --git a/crates/rbuilder/src/live_builder/block_output/relay_submit.rs b/crates/rbuilder/src/live_builder/block_output/relay_submit.rs index 01e1fda7..a1d96bcc 100644 --- a/crates/rbuilder/src/live_builder/block_output/relay_submit.rs +++ b/crates/rbuilder/src/live_builder/block_output/relay_submit.rs @@ -196,7 +196,7 @@ async fn run_submit_to_relays_job( block = block.sealed_block.number, hash = ?block.sealed_block.header.hash(), gas = block.sealed_block.gas_used, - txs = block.sealed_block.body.len(), + txs = block.sealed_block.body.transactions.len(), bundles, buidler_name = block.builder_name, fill_time_ms = block.trace.fill_time.as_millis(), @@ -213,6 +213,7 @@ async fn run_submit_to_relays_job( &config.signer, &block.sealed_block, &block.txs_blobs_sidecars, + &block.execution_requests, &config.chain_spec, &slot_data.payload_attributes_event.data, slot_data.slot_data.pubkey, @@ -228,6 +229,7 @@ async fn run_submit_to_relays_job( &config.optimistic_signer, &block.sealed_block, &block.txs_blobs_sidecars, + &block.execution_requests, &config.chain_spec, &slot_data.payload_attributes_event.data, slot_data.slot_data.pubkey, diff --git a/crates/rbuilder/src/live_builder/building/mod.rs b/crates/rbuilder/src/live_builder/building/mod.rs index 2aa1104a..640687d8 100644 --- a/crates/rbuilder/src/live_builder/building/mod.rs +++ b/crates/rbuilder/src/live_builder/building/mod.rs @@ -11,7 +11,7 @@ use crate::{ roothash::run_trie_prefetcher, }; use reth_db::Database; -use reth_provider::{DatabaseProviderFactory, StateProviderFactory}; +use reth_provider::{BlockReader, DatabaseProviderFactory, StateProviderFactory}; use tokio::sync::{broadcast, mpsc}; use tokio_util::sync::CancellationToken; use tracing::{debug, trace}; @@ -38,7 +38,10 @@ pub struct BlockBuildingPool { impl BlockBuildingPool where DB: Database + Clone + 'static, - P: DatabaseProviderFactory + StateProviderFactory + Clone + 'static, + P: DatabaseProviderFactory + + StateProviderFactory + + Clone + + 'static, { pub fn new( provider: P, diff --git a/crates/rbuilder/src/live_builder/cli.rs b/crates/rbuilder/src/live_builder/cli.rs index ac0a2ccc..6a34b584 100644 --- a/crates/rbuilder/src/live_builder/cli.rs +++ b/crates/rbuilder/src/live_builder/cli.rs @@ -1,9 +1,9 @@ use std::path::PathBuf; use clap::Parser; +use reth::revm::cached::CachedReads; use reth_db::Database; -use reth_payload_builder::database::CachedReads; -use reth_provider::{DatabaseProviderFactory, HeaderProvider, StateProviderFactory}; +use reth_provider::{BlockReader, DatabaseProviderFactory, HeaderProvider, StateProviderFactory}; use serde::de::DeserializeOwned; use std::fmt::Debug; use tokio::signal::ctrl_c; @@ -53,7 +53,11 @@ pub trait LiveBuilderConfig: Debug + DeserializeOwned + Sync { + Send where DB: Database + Clone + 'static, - P: DatabaseProviderFactory + StateProviderFactory + HeaderProvider + Clone + 'static; + P: DatabaseProviderFactory + + StateProviderFactory + + HeaderProvider + + Clone + + 'static; /// Patch until we have a unified way of backtesting using the exact algorithms we use on the LiveBuilder. /// building_algorithm_name will come from the specific configuration. @@ -64,7 +68,10 @@ pub trait LiveBuilderConfig: Debug + DeserializeOwned + Sync { ) -> eyre::Result<(Block, CachedReads)> where DB: Database + Clone + 'static, - P: DatabaseProviderFactory + StateProviderFactory + Clone + 'static; + P: DatabaseProviderFactory + + StateProviderFactory + + Clone + + 'static; } /// print_version_info func that will be called on command Cli::Version diff --git a/crates/rbuilder/src/live_builder/config.rs b/crates/rbuilder/src/live_builder/config.rs index 517940f8..508787d7 100644 --- a/crates/rbuilder/src/live_builder/config.rs +++ b/crates/rbuilder/src/live_builder/config.rs @@ -46,18 +46,20 @@ use ethereum_consensus::{ state_transition::Context as ContextEth, }; use eyre::Context; -use reth::tasks::pool::BlockingTaskPool; +use reth::revm::cached::CachedReads; use reth_chainspec::{Chain, ChainSpec, NamedChain}; use reth_db::{Database, DatabaseEnv}; -use reth_payload_builder::database::CachedReads; +use reth_node_api::NodeTypesWithDBAdapter; +use reth_node_ethereum::EthereumNode; use reth_primitives::StaticFileSegment; use reth_provider::{ - DatabaseProviderFactory, HeaderProvider, StateProviderFactory, StaticFileProviderFactory, + BlockReader, DatabaseProviderFactory, HeaderProvider, StateProviderFactory, + StaticFileProviderFactory, }; use serde::Deserialize; use serde_with::{serde_as, OneOrMany}; -use std::fmt::Debug; use std::{ + fmt::Debug, path::{Path, PathBuf}, str::FromStr, sync::Arc, @@ -295,7 +297,11 @@ impl LiveBuilderConfig for Config { ) -> eyre::Result> where DB: Database + Clone + 'static, - P: DatabaseProviderFactory + StateProviderFactory + HeaderProvider + Clone + 'static, + P: DatabaseProviderFactory + + StateProviderFactory + + HeaderProvider + + Clone + + 'static, { let (sink_sealed_factory, relays) = self.l1_config.create_relays_sealed_sink_factory( self.base_config.chain_spec()?, @@ -334,11 +340,9 @@ impl LiveBuilderConfig for Config { ) .await?; let root_hash_config = self.base_config.live_root_hash_config()?; - let root_hash_task_pool = self.base_config.root_hash_task_pool()?; let builders = create_builders( self.live_builders()?, root_hash_config, - root_hash_task_pool, self.base_config.sbundle_mergeabe_signers(), ); Ok(live_builder.with_builders(builders)) @@ -355,7 +359,10 @@ impl LiveBuilderConfig for Config { ) -> eyre::Result<(Block, CachedReads)> where DB: Database + Clone + 'static, - P: DatabaseProviderFactory + StateProviderFactory + Clone + 'static, + P: DatabaseProviderFactory + + StateProviderFactory + + Clone + + 'static, { let builder_cfg = self.builder(building_algorithm_name)?; match builder_cfg.builder { @@ -426,7 +433,7 @@ pub fn create_provider_factory( reth_db_path: Option<&Path>, reth_static_files_path: Option<&Path>, chain_spec: Arc, -) -> eyre::Result>> { +) -> eyre::Result>>> { let reth_db_path = match (reth_db_path, reth_datadir) { (Some(reth_db_path), _) => PathBuf::from(reth_db_path), (None, Some(reth_datadir)) => reth_datadir.join("db"), @@ -472,41 +479,37 @@ pub fn coinbase_signer_from_secret_key(secret_key: &str) -> eyre::Result pub fn create_builders( configs: Vec, root_hash_config: RootHashConfig, - root_hash_task_pool: BlockingTaskPool, sbundle_mergeabe_signers: Vec
, ) -> Vec>> where DB: Database + Clone + 'static, - P: DatabaseProviderFactory + StateProviderFactory + Clone + 'static, + P: DatabaseProviderFactory + + StateProviderFactory + + Clone + + 'static, { configs .into_iter() - .map(|cfg| { - create_builder( - cfg, - &root_hash_config, - &root_hash_task_pool, - &sbundle_mergeabe_signers, - ) - }) + .map(|cfg| create_builder(cfg, &root_hash_config, &sbundle_mergeabe_signers)) .collect() } fn create_builder( cfg: BuilderConfig, root_hash_config: &RootHashConfig, - root_hash_task_pool: &BlockingTaskPool, sbundle_mergeabe_signers: &[Address], ) -> Arc> where DB: Database + Clone + 'static, - P: DatabaseProviderFactory + StateProviderFactory + Clone + 'static, + P: DatabaseProviderFactory + + StateProviderFactory + + Clone + + 'static, { match cfg.builder { SpecificBuilderConfig::OrderingBuilder(order_cfg) => { Arc::new(OrderingBuildingAlgorithm::new( root_hash_config.clone(), - root_hash_task_pool.clone(), sbundle_mergeabe_signers.to_vec(), order_cfg, cfg.name, @@ -515,7 +518,6 @@ where SpecificBuilderConfig::ParallelBuilder(parallel_cfg) => { Arc::new(ParallelBuildingAlgorithm::new( root_hash_config.clone(), - root_hash_task_pool.clone(), sbundle_mergeabe_signers.to_vec(), parallel_cfg, cfg.name, diff --git a/crates/rbuilder/src/live_builder/mod.rs b/crates/rbuilder/src/live_builder/mod.rs index 83a3228b..8e9b3f06 100644 --- a/crates/rbuilder/src/live_builder/mod.rs +++ b/crates/rbuilder/src/live_builder/mod.rs @@ -31,9 +31,8 @@ use payload_events::MevBoostSlotData; use reth::{primitives::Header, providers::HeaderProvider}; use reth_chainspec::ChainSpec; use reth_db::Database; -use reth_provider::{DatabaseProviderFactory, StateProviderFactory}; -use std::fmt::Debug; -use std::{cmp::min, path::PathBuf, sync::Arc, time::Duration}; +use reth_provider::{BlockReader, DatabaseProviderFactory, StateProviderFactory}; +use std::{cmp::min, fmt::Debug, path::PathBuf, sync::Arc, time::Duration}; use time::OffsetDateTime; use tokio::sync::mpsc; use tokio_util::sync::CancellationToken; @@ -116,7 +115,11 @@ where impl LiveBuilder where DB: Database + Clone + 'static, - P: DatabaseProviderFactory + StateProviderFactory + HeaderProvider + Clone + 'static, + P: DatabaseProviderFactory + + StateProviderFactory + + HeaderProvider + + Clone + + 'static, BlocksSourceType: SlotSource, { pub fn with_extra_rpc(self, extra_rpc: RpcModule<()>) -> Self { @@ -227,7 +230,7 @@ where inc_active_slots(); - let block_ctx = BlockBuildingContext::from_attributes( + if let Some(block_ctx) = BlockBuildingContext::from_attributes( payload.payload_attributes_event.clone(), &parent_header, self.coinbase_signer.clone(), @@ -236,16 +239,16 @@ where Some(payload.suggested_gas_limit), self.extra_data.clone(), None, - ); - - builder_pool.start_block_building( - payload, - block_ctx, - self.global_cancellation.clone(), - time_until_slot_end.try_into().unwrap_or_default(), - ); + ) { + builder_pool.start_block_building( + payload, + block_ctx, + self.global_cancellation.clone(), + time_until_slot_end.try_into().unwrap_or_default(), + ); - watchdog_sender.try_send(()).unwrap_or_default(); + watchdog_sender.try_send(()).unwrap_or_default(); + } } info!("Builder shutting down"); diff --git a/crates/rbuilder/src/live_builder/order_input/orderpool.rs b/crates/rbuilder/src/live_builder/order_input/orderpool.rs index de9c6693..083caa9c 100644 --- a/crates/rbuilder/src/live_builder/order_input/orderpool.rs +++ b/crates/rbuilder/src/live_builder/order_input/orderpool.rs @@ -3,8 +3,9 @@ use crate::primitives::{ ShareBundleReplacementKey, }; use ahash::HashMap; +use alloy_eips::merge::SLOT_DURATION; use lru::LruCache; -use reth::{primitives::constants::SLOT_DURATION, providers::StateProviderBox}; +use reth::providers::StateProviderBox; use std::{ collections::VecDeque, num::NonZeroUsize, diff --git a/crates/rbuilder/src/live_builder/order_input/rpc_server.rs b/crates/rbuilder/src/live_builder/order_input/rpc_server.rs index 5b37cf18..25a1d64b 100644 --- a/crates/rbuilder/src/live_builder/order_input/rpc_server.rs +++ b/crates/rbuilder/src/live_builder/order_input/rpc_server.rs @@ -3,9 +3,8 @@ use crate::primitives::{ serialize::{RawBundle, RawShareBundle, RawShareBundleDecodeResult, RawTx, TxEncoding}, Bundle, BundleReplacementKey, MempoolTx, Order, }; -use alloy_primitives::Address; +use alloy_primitives::{Address, Bytes}; use jsonrpsee::{server::Server, types::ErrorObject, RpcModule}; -use reth_primitives::Bytes; use serde::Deserialize; use std::{ net::{SocketAddr, SocketAddrV4}, diff --git a/crates/rbuilder/src/live_builder/order_input/txpool_fetcher.rs b/crates/rbuilder/src/live_builder/order_input/txpool_fetcher.rs index 264f449a..861c7a3b 100644 --- a/crates/rbuilder/src/live_builder/order_input/txpool_fetcher.rs +++ b/crates/rbuilder/src/live_builder/order_input/txpool_fetcher.rs @@ -157,13 +157,15 @@ mod test { let gas_price = provider.get_gas_price().await.unwrap(); let eip1559_est = provider.estimate_eip1559_fees(None).await.unwrap(); - let tx = TransactionRequest::default() - .with_to(alice) - .with_nonce(0) - .with_max_fee_per_blob_gas(gas_price) - .with_max_fee_per_gas(eip1559_est.max_fee_per_gas) - .with_max_priority_fee_per_gas(eip1559_est.max_priority_fee_per_gas) - .with_blob_sidecar(sidecar); + let tx = TransactionRequest { + max_fee_per_blob_gas: Some(gas_price), + sidecar: Some(sidecar), + ..TransactionRequest::default() + .with_to(alice) + .with_nonce(0) + .with_max_fee_per_gas(eip1559_est.max_fee_per_gas) + .with_max_priority_fee_per_gas(eip1559_est.max_priority_fee_per_gas) + }; let pending_tx = provider.send_transaction(tx).await.unwrap(); let recv_tx = receiver.recv().await.unwrap(); diff --git a/crates/rbuilder/src/live_builder/payload_events/mod.rs b/crates/rbuilder/src/live_builder/payload_events/mod.rs index 2369be45..d1285f08 100644 --- a/crates/rbuilder/src/live_builder/payload_events/mod.rs +++ b/crates/rbuilder/src/live_builder/payload_events/mod.rs @@ -17,10 +17,9 @@ use crate::{ primitives::mev_boost::{MevBoostRelay, MevBoostRelayID}, }; use ahash::HashSet; +use alloy_eips::merge::SLOT_DURATION; use alloy_primitives::{utils::format_ether, Address, B256, U256}; -use reth::{ - primitives::constants::SLOT_DURATION, rpc::types::beacon::events::PayloadAttributesEvent, -}; +use alloy_rpc_types_beacon::events::PayloadAttributesEvent; use std::{collections::VecDeque, time::Duration}; use tokio::{sync::mpsc, task::JoinHandle}; use tokio_util::sync::CancellationToken; diff --git a/crates/rbuilder/src/live_builder/payload_events/payload_source.rs b/crates/rbuilder/src/live_builder/payload_events/payload_source.rs index 01d6328b..c1aa3a55 100644 --- a/crates/rbuilder/src/live_builder/payload_events/payload_source.rs +++ b/crates/rbuilder/src/live_builder/payload_events/payload_source.rs @@ -1,6 +1,6 @@ use crate::beacon_api_client::{Client, PayloadAttributesTopic}; +use alloy_rpc_types_beacon::events::PayloadAttributesEvent; use futures::future::join_all; -use reth::rpc::types::beacon::events::PayloadAttributesEvent; use tokio::{ sync::mpsc::{self, UnboundedSender}, diff --git a/crates/rbuilder/src/live_builder/simulation/mod.rs b/crates/rbuilder/src/live_builder/simulation/mod.rs index ec40a408..5e17a06d 100644 --- a/crates/rbuilder/src/live_builder/simulation/mod.rs +++ b/crates/rbuilder/src/live_builder/simulation/mod.rs @@ -167,7 +167,7 @@ mod tests { primitives::{MempoolTx, Order, TransactionSignedEcRecoveredWithBlobs}, utils::ProviderFactoryReopener, }; - use reth_primitives::U256; + use alloy_primitives::U256; #[tokio::test] async fn test_simulate_order_to_coinbase() { diff --git a/crates/rbuilder/src/live_builder/simulation/sim_worker.rs b/crates/rbuilder/src/live_builder/simulation/sim_worker.rs index fa3ac9b3..d37342b1 100644 --- a/crates/rbuilder/src/live_builder/simulation/sim_worker.rs +++ b/crates/rbuilder/src/live_builder/simulation/sim_worker.rs @@ -7,7 +7,7 @@ use crate::{ telemetry, telemetry::add_sim_thread_utilisation_timings, }; -use reth_payload_builder::database::CachedReads; +use reth::revm::cached::CachedReads; use reth_provider::StateProviderFactory; use std::{ sync::{Arc, Mutex}, diff --git a/crates/rbuilder/src/mev_boost/rpc.rs b/crates/rbuilder/src/mev_boost/rpc.rs index 399cb095..511af772 100644 --- a/crates/rbuilder/src/mev_boost/rpc.rs +++ b/crates/rbuilder/src/mev_boost/rpc.rs @@ -2,6 +2,7 @@ use super::DenebSubmitBlockRequest; use alloy_consensus::{Blob, Bytes48}; use alloy_primitives::{Address, Bloom, Bytes, B256, U256}; use alloy_rpc_types_beacon::{ + events::PayloadAttributesData, relay::{BidTrace, SignedBidSubmissionV3}, BlsPublicKey, BlsSignature, }; @@ -9,8 +10,7 @@ use alloy_rpc_types_engine::{ BlobsBundleV1, ExecutionPayloadV1, ExecutionPayloadV2, ExecutionPayloadV3, }; use alloy_rpc_types_eth::Withdrawal; -use reth::rpc::types::{beacon::events::PayloadAttributesData, engine::PayloadAttributes}; - +use reth::rpc::types::engine::PayloadAttributes; /// TestDataGenerator allows you to create unique test objects with unique content, it tries to use different numbers for every field it sets #[derive(Default)] pub struct TestDataGenerator { diff --git a/crates/rbuilder/src/mev_boost/sign_payload.rs b/crates/rbuilder/src/mev_boost/sign_payload.rs index acf56dee..ee43c826 100644 --- a/crates/rbuilder/src/mev_boost/sign_payload.rs +++ b/crates/rbuilder/src/mev_boost/sign_payload.rs @@ -3,13 +3,15 @@ use super::{ SubmitBlockRequest, }; use crate::utils::u256decimal_serde_helper; -use alloy_primitives::{Address, BlockHash, FixedBytes, B256, U256}; +use alloy_eips::eip2718::Encodable2718; +use alloy_primitives::{Address, BlockHash, Bytes, FixedBytes, B256, U256}; use alloy_rpc_types_beacon::{ + events::PayloadAttributesData, relay::{BidTrace, SignedBidSubmissionV2, SignedBidSubmissionV3, SignedBidSubmissionV4}, BlsPublicKey, }; use alloy_rpc_types_engine::{ - BlobsBundleV1, ExecutionPayloadV1, ExecutionPayloadV2, ExecutionPayloadV3, ExecutionPayloadV4, + BlobsBundleV1, ExecutionPayloadV1, ExecutionPayloadV2, ExecutionPayloadV3, }; use alloy_rpc_types_eth::Withdrawal; use ethereum_consensus::{ @@ -19,7 +21,6 @@ use ethereum_consensus::{ ssz::prelude::*, }; use primitive_types::H384; -use reth::rpc::types::beacon::events::PayloadAttributesData; use reth_chainspec::{ChainSpec, EthereumHardforks}; use reth_primitives::{BlobTransactionSidecar, SealedBlock}; use serde_with::{serde_as, DisplayFromStr}; @@ -107,10 +108,12 @@ fn a2e_address(a: &Address) -> ExecutionAddress { ExecutionAddress::try_from(a.as_slice()).unwrap() } +#[allow(clippy::too_many_arguments)] pub fn sign_block_for_relay( signer: &BLSBlockSigner, sealed_block: &SealedBlock, blobs_bundle: &[Arc], + execution_requests: &[Bytes], // The Pectra execution requests for this bid. chain_spec: &ChainSpec, attrs: &PayloadAttributesData, pubkey: H384, @@ -148,11 +151,17 @@ pub fn sign_block_for_relay( block_hash: sealed_block.hash(), transactions: sealed_block .body + .transactions .iter() - .map(|tx| tx.envelope_encoded().to_vec().into()) + .map(|tx| { + let mut buf = Vec::new(); + tx.encode_2718(&mut buf); + buf.into() + }) .collect(), }, withdrawals: sealed_block + .body .withdrawals .clone() .map(|w| { @@ -182,35 +191,12 @@ pub fn sign_block_for_relay( let blobs_bundle = marshal_txs_blobs_sidecars(blobs_bundle); if chain_spec.is_prague_active_at_timestamp(sealed_block.timestamp) { - let mut deposit_requests = Vec::new(); - let mut withdrawal_requests = Vec::new(); - let mut consolidation_requests = Vec::new(); - for request in sealed_block.requests.iter().flat_map(|r| &r.0) { - match request { - alloy_consensus::Request::DepositRequest(r) => { - deposit_requests.push(*r); - } - alloy_consensus::Request::WithdrawalRequest(r) => { - withdrawal_requests.push(*r); - } - alloy_consensus::Request::ConsolidationRequest(r) => { - consolidation_requests.push(*r); - } - _ => {} - }; - } - - let execution_payload = ExecutionPayloadV4 { - payload_inner: execution_payload, - deposit_requests, - withdrawal_requests, - consolidation_requests, - }; SubmitBlockRequest::Electra(ElectraSubmitBlockRequest(SignedBidSubmissionV4 { message, execution_payload, blobs_bundle, signature, + execution_requests: execution_requests.to_vec(), })) } else { SubmitBlockRequest::Deneb(DenebSubmitBlockRequest(SignedBidSubmissionV3 { diff --git a/crates/rbuilder/src/primitives/fmt.rs b/crates/rbuilder/src/primitives/fmt.rs index 2da6ce3c..e39bb195 100644 --- a/crates/rbuilder/src/primitives/fmt.rs +++ b/crates/rbuilder/src/primitives/fmt.rs @@ -14,7 +14,7 @@ pub fn write_share_bundle_tx( "TX {} Rev {:?} val {}\n", tx.tx.hash(), tx.revert_behavior, - tx.tx.tx.value() + tx.tx.value() )) } @@ -45,7 +45,7 @@ pub fn write_order( Order::Tx(tx) => buf.write_str(&format!( "Tx {} val {}\n", tx.tx_with_blobs.hash(), - tx.tx_with_blobs.tx.value() + tx.tx_with_blobs.value() )), Order::ShareBundle(sb) => { buf.write_str(&format!("ShB {:?}\n", sb.hash))?; diff --git a/crates/rbuilder/src/primitives/mod.rs b/crates/rbuilder/src/primitives/mod.rs index 4486e0d0..32132f70 100644 --- a/crates/rbuilder/src/primitives/mod.rs +++ b/crates/rbuilder/src/primitives/mod.rs @@ -7,17 +7,19 @@ pub mod serialize; mod test_data_generator; use crate::building::evm_inspector::UsedStateTrace; -use alloy_eips::eip4844::{Blob, Bytes48}; -use alloy_primitives::{Bytes, TxHash}; +use alloy_consensus::Transaction as _; +use alloy_eips::{ + eip2718::{Decodable2718, Eip2718Error, Encodable2718}, + eip4844::{Blob, Bytes48}, +}; +use alloy_primitives::{keccak256, Address, Bytes, TxHash, B256, U256}; use derivative::Derivative; use integer_encoding::VarInt; use reth_primitives::{ - keccak256, kzg::{BYTES_PER_BLOB, BYTES_PER_COMMITMENT, BYTES_PER_PROOF}, - Address, BlobTransactionSidecar, PooledTransactionsElement, TransactionSigned, - TransactionSignedEcRecovered, B256, + BlobTransactionSidecar, PooledTransactionsElement, TransactionSigned, + TransactionSignedEcRecovered, }; -use revm_primitives::U256; use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; use std::{cmp::Ordering, collections::HashMap, fmt::Display, str::FromStr, sync::Arc}; @@ -429,7 +431,7 @@ impl std::fmt::Debug for TransactionSignedEcRecoveredWithBlobs { #[derive(Error, Debug)] pub enum RawTxWithBlobsConvertError { #[error("Failed to decode transaction, error: {0}")] - FailedToDecodeTransaction(alloy_rlp::Error), + FailedToDecodeTransaction(Eip2718Error), #[error("Invalid transaction signature")] InvalidTransactionSignature, #[error("Invalid transaction signature")] @@ -467,7 +469,11 @@ impl TransactionSignedEcRecoveredWithBlobs { } pub fn nonce(&self) -> u64 { - self.tx.nonce() + self.tx.as_signed().nonce() + } + + pub fn value(&self) -> U256 { + self.tx.as_signed().value() } /// USE CAREFULLY since this exposes the signed tx. @@ -484,7 +490,9 @@ impl TransactionSignedEcRecoveredWithBlobs { /// I intensionally omitted the version with blob data since we don't use it and may lead to confusions/bugs. /// USE CAREFULLY since this exposes the signed tx. pub fn envelope_encoded_no_blobs(&self) -> Bytes { - self.tx.envelope_encoded() + let mut buf = Vec::new(); + self.tx.as_signed().encode_2718(&mut buf); + buf.into() } /// Decodes the "raw" format of transaction (e.g. `eth_sendRawTransaction`) with the blob data (network format) @@ -493,7 +501,7 @@ impl TransactionSignedEcRecoveredWithBlobs { ) -> Result { let raw_tx = &mut raw_tx.as_ref(); let pooled_tx: PooledTransactionsElement = - PooledTransactionsElement::decode_enveloped(raw_tx) + PooledTransactionsElement::decode_2718(raw_tx) .map_err(RawTxWithBlobsConvertError::FailedToDecodeTransaction)?; let signer = pooled_tx .recover_signer() @@ -545,7 +553,7 @@ impl TransactionSignedEcRecoveredWithBlobs { pub fn decode_enveloped_with_fake_blobs( raw_tx: Bytes, ) -> Result { - let decoded = TransactionSigned::decode_enveloped(&mut raw_tx.as_ref()) + let decoded = TransactionSigned::decode_2718(&mut raw_tx.as_ref()) .map_err(RawTxWithBlobsConvertError::FailedToDecodeTransaction)?; let tx = decoded .into_ecrecovered() @@ -928,8 +936,9 @@ fn can_execute_with_block_base_fee>( #[cfg(test)] mod tests { use super::*; + use alloy_consensus::TxLegacy; use alloy_primitives::fixed_bytes; - use reth_primitives::{Transaction, TransactionSigned, TxLegacy}; + use reth_primitives::{Transaction, TransactionSigned}; use uuid::uuid; #[test] diff --git a/crates/rbuilder/src/primitives/serialize.rs b/crates/rbuilder/src/primitives/serialize.rs index 8ba77c1b..0260d8b7 100644 --- a/crates/rbuilder/src/primitives/serialize.rs +++ b/crates/rbuilder/src/primitives/serialize.rs @@ -4,8 +4,7 @@ use super::{ ShareBundleInner, ShareBundleReplacementData, ShareBundleReplacementKey, ShareBundleTx, TransactionSignedEcRecoveredWithBlobs, TxRevertBehavior, }; -use alloy_primitives::Address; -use reth_primitives::{Bytes, B256, U64}; +use alloy_primitives::{Address, Bytes, B256, U64}; use serde::{Deserialize, Serialize}; use serde_with::{serde_as, DefaultOnNull}; use thiserror::Error; @@ -544,6 +543,8 @@ impl From for RawOrder { #[cfg(test)] mod tests { use super::*; + use alloy_consensus::Transaction; + use alloy_eips::eip2718::Encodable2718; use alloy_primitives::{address, fixed_bytes, keccak256, U256}; use uuid::uuid; @@ -682,7 +683,11 @@ mod tests { .tx; let raw_tx_roundtrip = RawTx { - tx: tx.envelope_encoded(), + tx: { + let mut buf = Vec::new(); + tx.as_signed().encode_2718(&mut buf); + buf.into() + }, }; assert_eq!(raw_tx_request, raw_tx_roundtrip); diff --git a/crates/rbuilder/src/primitives/test_data_generator.rs b/crates/rbuilder/src/primitives/test_data_generator.rs index ec98fb8c..05166164 100644 --- a/crates/rbuilder/src/primitives/test_data_generator.rs +++ b/crates/rbuilder/src/primitives/test_data_generator.rs @@ -1,5 +1,6 @@ +use alloy_consensus::TxLegacy; use alloy_primitives::B256; -use reth_primitives::{Transaction, TransactionSigned, TransactionSignedEcRecovered, TxLegacy}; +use reth_primitives::{Transaction, TransactionSigned, TransactionSignedEcRecovered}; use uuid::Uuid; use super::{ diff --git a/crates/rbuilder/src/roothash/mod.rs b/crates/rbuilder/src/roothash/mod.rs index b9a0bc08..9d5fea1e 100644 --- a/crates/rbuilder/src/roothash/mod.rs +++ b/crates/rbuilder/src/roothash/mod.rs @@ -5,14 +5,11 @@ use eth_sparse_mpt::reth_sparse_trie::{ calculate_root_hash_with_sparse_trie, trie_fetcher::FetchNodeError, SparseTrieError, SparseTrieSharedCache, }; -use reth::{ - providers::{providers::ConsistentDbView, ExecutionOutcome}, - tasks::pool::BlockingTaskPool, -}; -use reth_db::database::Database; +use reth::providers::{providers::ConsistentDbView, ExecutionOutcome}; use reth_errors::ProviderError; -use reth_provider::DatabaseProviderFactory; -use reth_trie_parallel::async_root::{AsyncStateRoot, AsyncStateRootError}; +use reth_provider::{BlockReader, DatabaseProviderFactory}; +use reth_trie::TrieInput; +use reth_trie_parallel::parallel_root::{ParallelStateRoot, ParallelStateRootError}; use tracing::trace; pub use prefetcher::run_trie_prefetcher; @@ -33,7 +30,7 @@ pub enum RootHashMode { #[derive(Debug, thiserror::Error)] pub enum RootHashError { #[error("Async state root: {0:?}")] - AsyncStateRoot(#[from] AsyncStateRootError), + AsyncStateRoot(#[from] ParallelStateRootError), #[error("Sparse state root: {0:?}")] SparseStateRoot(#[from] SparseTrieError), #[error("State root verification error")] @@ -45,7 +42,7 @@ impl RootHashError { /// This often happens when building for block after it was proposed. pub fn is_consistent_db_view_err(&self) -> bool { let provider_error = match self { - RootHashError::AsyncStateRoot(AsyncStateRootError::Provider(p)) => p, + RootHashError::AsyncStateRoot(ParallelStateRootError::Provider(p)) => p, RootHashError::SparseStateRoot(SparseTrieError::FetchNode( FetchNodeError::Provider(p), )) => p, @@ -81,38 +78,44 @@ impl RootHashConfig { } } +fn calculate_parallel_root_hash

( + outcome: &ExecutionOutcome, + consistent_db_view: ConsistentDbView

, +) -> Result +where + P: DatabaseProviderFactory + Send + Sync + Clone + 'static, +{ + let hashed_post_state = outcome.hash_state_slow(); + + let parallel_root_calculator = ParallelStateRoot::new( + consistent_db_view.clone(), + TrieInput::from_state(hashed_post_state), + ); + parallel_root_calculator.incremental_root() +} + #[allow(clippy::too_many_arguments)] -pub fn calculate_state_root( +pub fn calculate_state_root

( provider: P, parent_hash: B256, outcome: &ExecutionOutcome, - blocking_task_pool: BlockingTaskPool, sparse_trie_shared_cache: SparseTrieSharedCache, config: RootHashConfig, ) -> Result where - DB: Database + Clone + 'static, - P: DatabaseProviderFactory + Clone + Sync + Send + 'static, + P: DatabaseProviderFactory + Send + Sync + Clone + 'static, { let consistent_db_view = match config.mode { RootHashMode::CorrectRoot => ConsistentDbView::new(provider, Some(parent_hash)), RootHashMode::IgnoreParentHash => ConsistentDbView::new_with_latest_tip(provider) - .map_err(AsyncStateRootError::Provider)?, + .map_err(ParallelStateRootError::Provider)?, RootHashMode::SkipRootHash => { return Ok(B256::ZERO); } }; let reference_root_hash = if config.compare_sparse_trie_output { - let hashed_post_state = outcome.hash_state_slow(); - - let async_root_calculator = AsyncStateRoot::new( - consistent_db_view.clone(), - blocking_task_pool.clone(), - hashed_post_state.clone(), - ); - - futures::executor::block_on(async_root_calculator.incremental_root())? + calculate_parallel_root_hash(outcome, consistent_db_view.clone())? } else { B256::ZERO }; @@ -126,12 +129,7 @@ where trace!(?metrics, "Sparse trie metrics"); root? } else { - let hashed_post_state = outcome.hash_state_slow(); - - let async_root_calculator = - AsyncStateRoot::new(consistent_db_view, blocking_task_pool, hashed_post_state); - - futures::executor::block_on(async_root_calculator.incremental_root())? + calculate_parallel_root_hash(outcome, consistent_db_view)? }; if config.compare_sparse_trie_output && reference_root_hash != root { diff --git a/crates/rbuilder/src/roothash/prefetcher.rs b/crates/rbuilder/src/roothash/prefetcher.rs index b9b4dab7..45210855 100644 --- a/crates/rbuilder/src/roothash/prefetcher.rs +++ b/crates/rbuilder/src/roothash/prefetcher.rs @@ -8,9 +8,8 @@ use eth_sparse_mpt::{ ChangedAccountData, }; use reth::providers::providers::ConsistentDbView; -use reth_db::database::Database; use reth_errors::ProviderError; -use reth_provider::DatabaseProviderFactory; +use reth_provider::{BlockReader, DatabaseProviderFactory}; use tokio::sync::broadcast::{ self, error::{RecvError, TryRecvError}, @@ -27,15 +26,14 @@ const CONSUME_SIM_ORDERS_BATCH: usize = 128; /// Runs a process that prefetches pieces of the trie based on the slots used by the order in simulation /// Its a blocking call so it should be spawned on the separate thread. -pub fn run_trie_prefetcher( +pub fn run_trie_prefetcher

( parent_hash: B256, shared_sparse_mpt_cache: SparseTrieSharedCache, provider: P, mut simulated_orders: broadcast::Receiver, cancel: CancellationToken, ) where - P: DatabaseProviderFactory + Clone + Send + Sync, - DB: Database + Clone + 'static, + P: DatabaseProviderFactory + Send + Sync + Clone, { let consistent_db_view = ConsistentDbView::new(provider, Some(parent_hash)); diff --git a/crates/rbuilder/src/utils/mod.rs b/crates/rbuilder/src/utils/mod.rs index 97af06f9..5112ce77 100644 --- a/crates/rbuilder/src/utils/mod.rs +++ b/crates/rbuilder/src/utils/mod.rs @@ -84,8 +84,8 @@ pub fn get_percent(value: U256, percent: usize) -> U256 { (value * U256::from(percent)) / U256::from(100) } -pub fn a2r_withdrawal(w: alloy_rpc_types::Withdrawal) -> reth_primitives::Withdrawal { - reth_primitives::Withdrawal { +pub fn a2r_withdrawal(w: alloy_rpc_types::Withdrawal) -> alloy_eips::eip4895::Withdrawal { + alloy_eips::eip4895::Withdrawal { index: w.index, validator_index: w.validator_index, address: w.address, diff --git a/crates/rbuilder/src/utils/provider_factory_reopen.rs b/crates/rbuilder/src/utils/provider_factory_reopen.rs index 237cc6a9..1e4c674d 100644 --- a/crates/rbuilder/src/utils/provider_factory_reopen.rs +++ b/crates/rbuilder/src/utils/provider_factory_reopen.rs @@ -1,14 +1,16 @@ use crate::telemetry::{inc_provider_bad_reopen_counter, inc_provider_reopen_counter}; use alloy_eips::{BlockNumHash, BlockNumberOrTag}; +use alloy_primitives::{BlockHash, BlockNumber}; use reth::providers::{BlockHashReader, ChainSpecProvider, ProviderFactory}; -use reth_chainspec::{ChainInfo, ChainSpec}; -use reth_db::{database::Database, DatabaseError}; +use reth_chainspec::ChainInfo; +use reth_db::{Database, DatabaseError}; use reth_errors::{ProviderError, ProviderResult, RethResult}; -use reth_primitives::{BlockHash, BlockNumber, Header, SealedHeader}; +use reth_node_api::NodeTypesWithDB; +use reth_primitives::{Header, SealedHeader}; use reth_provider::{ - providers::StaticFileProvider, BlockIdReader, BlockNumReader, DatabaseProviderFactory, - DatabaseProviderRO, HeaderProvider, StateProviderBox, StateProviderFactory, - StaticFileProviderFactory, + providers::{ProviderNodeTypes, StaticFileProvider}, + BlockIdReader, BlockNumReader, DatabaseProvider, DatabaseProviderFactory, DatabaseProviderRO, + HeaderProvider, StateProviderBox, StateProviderFactory, StaticFileProviderFactory, }; use revm_primitives::{B256, U256}; use std::{ @@ -23,9 +25,9 @@ use tracing::debug; /// This struct should be used on the level of the whole program and ProviderFactory should be extracted from it /// into the methods that has a lifetime of a slot (e.g. building particular block). #[derive(Debug, Clone)] -pub struct ProviderFactoryReopener { - provider_factory: Arc>>, - chain_spec: Arc, +pub struct ProviderFactoryReopener { + provider_factory: Arc>>, + chain_spec: Arc, static_files_path: PathBuf, /// Last block the Reopener verified consistency for. last_consistent_block: Arc>>, @@ -33,12 +35,16 @@ pub struct ProviderFactoryReopener { testing_mode: bool, } -impl ProviderFactoryReopener { - pub fn new(db: DB, chain_spec: Arc, static_files_path: PathBuf) -> RethResult { +impl ProviderFactoryReopener { + pub fn new( + db: N::DB, + chain_spec: Arc, + static_files_path: PathBuf, + ) -> RethResult { let provider_factory = ProviderFactory::new( db, chain_spec.clone(), - StaticFileProvider::read_only(static_files_path.as_path()).unwrap(), + StaticFileProvider::read_only(static_files_path.as_path(), true).unwrap(), ); Ok(Self { @@ -50,7 +56,7 @@ impl ProviderFactoryReopener { }) } - pub fn new_from_existing(provider_factory: ProviderFactory) -> RethResult { + pub fn new_from_existing(provider_factory: ProviderFactory) -> RethResult { let chain_spec = provider_factory.chain_spec(); let static_files_path = provider_factory.static_file_provider().path().to_path_buf(); Ok(Self { @@ -64,7 +70,7 @@ impl ProviderFactoryReopener { /// This will currently available provider factory without verifying if its correct, it can be used /// when consistency is not absolutely required - pub fn provider_factory_unchecked(&self) -> ProviderFactory { + pub fn provider_factory_unchecked(&self) -> ProviderFactory { self.provider_factory.lock().unwrap().clone() } @@ -74,7 +80,7 @@ impl ProviderFactoryReopener { /// /// If the current block number is already known at the time of calling this method, you may pass it to /// avoid an additional DB lookup for the latest block number. - pub fn check_consistency_and_reopen_if_needed(&self) -> eyre::Result> { + pub fn check_consistency_and_reopen_if_needed(&self) -> eyre::Result> { let best_block_number = self .provider_factory_unchecked() .last_block_number() @@ -96,7 +102,8 @@ impl ProviderFactoryReopener { *provider_factory = ProviderFactory::new( provider_factory.db_ref().clone(), self.chain_spec.clone(), - StaticFileProvider::read_only(self.static_files_path.as_path()).unwrap(), + StaticFileProvider::read_only(self.static_files_path.as_path(), true) + .unwrap(), ); } } @@ -129,9 +136,9 @@ pub fn is_provider_factory_health_error(report: &eyre::Error) -> bool { /// Here we check if we have all the necessary historical block hashes in the database /// This was added as a debugging method because static_files storage was not working correctly -pub fn check_provider_factory_health( +pub fn check_provider_factory_health( current_block_number: u64, - provider_factory: &ProviderFactory, + provider_factory: &ProviderFactory, ) -> eyre::Result<()> { // evm must have access to block hashes of 256 of the previous blocks let blocks_to_check = current_block_number.min(256); @@ -156,8 +163,22 @@ pub fn check_provider_factory_health( // ProviderFactory only has access to disk state, therefore cannot implement methods // that require the blockchain tree (pending state etc.). -impl DatabaseProviderFactory for ProviderFactoryReopener { - fn database_provider_ro(&self) -> ProviderResult> { +impl DatabaseProviderFactory + for ProviderFactoryReopener +{ + /// Database this factory produces providers for. + type DB = N::DB; + /// Provider type returned by the factory. + type Provider = DatabaseProviderRO; + /// Read-write provider type returned by the factory. + type ProviderRW = DatabaseProvider<::TXMut, N>; + + /// Create new read-write database provider. + fn database_provider_rw(&self) -> ProviderResult { + unimplemented!("This method is not supported by ProviderFactoryReopener. We don't write."); + } + + fn database_provider_ro(&self) -> ProviderResult { let provider = self .check_consistency_and_reopen_if_needed() .map_err(|e| ProviderError::Database(DatabaseError::Other(e.to_string())))?; @@ -165,7 +186,7 @@ impl DatabaseProviderFactory for ProviderFactoryReopen } } -impl HeaderProvider for ProviderFactoryReopener { +impl HeaderProvider for ProviderFactoryReopener { fn header(&self, block_hash: &BlockHash) -> ProviderResult> { let provider = self .check_consistency_and_reopen_if_needed() @@ -220,7 +241,9 @@ impl HeaderProvider for ProviderFactoryReopener { } } -impl BlockHashReader for ProviderFactoryReopener { +impl BlockHashReader + for ProviderFactoryReopener +{ fn block_hash(&self, number: BlockNumber) -> ProviderResult> { let provider = self .check_consistency_and_reopen_if_needed() @@ -240,7 +263,7 @@ impl BlockHashReader for ProviderFactoryReopener { } } -impl BlockNumReader for ProviderFactoryReopener { +impl BlockNumReader for ProviderFactoryReopener { fn chain_info(&self) -> ProviderResult { let provider = self .check_consistency_and_reopen_if_needed() @@ -270,7 +293,7 @@ impl BlockNumReader for ProviderFactoryReopener { } } -impl BlockIdReader for ProviderFactoryReopener { +impl BlockIdReader for ProviderFactoryReopener { fn pending_block_num_hash(&self) -> ProviderResult> { unimplemented!("This method is not supported by ProviderFactoryReopener. Please consider using a BlockchainProvider."); } @@ -284,7 +307,9 @@ impl BlockIdReader for ProviderFactoryReopener { } } -impl StateProviderFactory for ProviderFactoryReopener { +impl StateProviderFactory + for ProviderFactoryReopener +{ fn latest(&self) -> ProviderResult { let provider = self .check_consistency_and_reopen_if_needed() diff --git a/crates/rbuilder/src/utils/test_utils.rs b/crates/rbuilder/src/utils/test_utils.rs index ab960b04..17d517ed 100644 --- a/crates/rbuilder/src/utils/test_utils.rs +++ b/crates/rbuilder/src/utils/test_utils.rs @@ -27,7 +27,7 @@ pub fn tx(tx_hash: u64) -> TransactionSignedEcRecoveredWithBlobs { TransactionSignedEcRecovered::from_signed_transaction( TransactionSigned { hash: hash(tx_hash), - signature: Default::default(), + signature: alloy_primitives::Signature::test_signature(), transaction: Default::default(), }, Address::default(), diff --git a/crates/rbuilder/src/utils/tx_signer.rs b/crates/rbuilder/src/utils/tx_signer.rs index 766078c0..697ae38f 100644 --- a/crates/rbuilder/src/utils/tx_signer.rs +++ b/crates/rbuilder/src/utils/tx_signer.rs @@ -1,6 +1,6 @@ -use alloy_primitives::{Address, B256, U256}; +use alloy_primitives::{Address, Parity, Signature, B256, U256}; use reth_primitives::{ - public_key_to_address, Signature, Transaction, TransactionSigned, TransactionSignedEcRecovered, + public_key_to_address, Transaction, TransactionSigned, TransactionSignedEcRecovered, }; use secp256k1::{Message, SecretKey, SECP256K1}; @@ -26,11 +26,11 @@ impl Signer { .sign_ecdsa_recoverable(&Message::from_digest_slice(&message[..])?, &self.secret); let (rec_id, data) = s.serialize_compact(); - let signature = Signature { - r: U256::try_from_be_slice(&data[..32]).expect("The slice has at most 32 bytes"), - s: U256::try_from_be_slice(&data[32..64]).expect("The slice has at most 32 bytes"), - odd_y_parity: rec_id.to_i32() != 0, - }; + let signature = Signature::new( + U256::try_from_be_slice(&data[..32]).expect("The slice has at most 32 bytes"), + U256::try_from_be_slice(&data[32..64]).expect("The slice has at most 32 bytes"), + Parity::Parity(rec_id.to_i32() != 0), + ); Ok(signature) } @@ -54,9 +54,8 @@ impl Signer { #[cfg(test)] mod test { use super::*; - use alloy_primitives::{address, fixed_bytes}; - use reth_primitives::{TxEip1559, TxKind as TransactionKind}; - + use alloy_consensus::TxEip1559; + use alloy_primitives::{address, fixed_bytes, TxKind as TransactionKind}; #[test] fn test_sign_transaction() { let secret = diff --git a/crates/reth-rbuilder/Cargo.toml b/crates/reth-rbuilder/Cargo.toml index d56bcf9f..70bfea36 100644 --- a/crates/reth-rbuilder/Cargo.toml +++ b/crates/reth-rbuilder/Cargo.toml @@ -23,4 +23,6 @@ tikv-jemallocator = { workspace = true, optional = true } libc.workspace = true [features] -jemalloc = [] +jemalloc = [ + "reth-cli-util/jemalloc" +] diff --git a/crates/reth-rbuilder/src/main.rs b/crates/reth-rbuilder/src/main.rs index 9aac13bf..b44c1c15 100644 --- a/crates/reth-rbuilder/src/main.rs +++ b/crates/reth-rbuilder/src/main.rs @@ -5,18 +5,27 @@ //! Note this method of running rbuilder is not quite ready for production. //! See for more information. -use clap::Args; +use clap::{Args, Parser}; use rbuilder::{ live_builder::{base_config::load_config_toml_and_env, cli::LiveBuilderConfig, config::Config}, telemetry, }; +use reth::{chainspec::EthereumChainSpecParser, cli::Cli}; use reth_db_api::Database; +use reth_node_builder::{ + engine_tree_config::{ + TreeConfig, DEFAULT_MEMORY_BLOCK_BUFFER_TARGET, DEFAULT_PERSISTENCE_THRESHOLD, + }, + EngineNodeLauncher, +}; +use reth_node_ethereum::{node::EthereumAddOns, EthereumNode}; use reth_provider::{ - providers::BlockchainProvider, DatabaseProviderFactory, HeaderProvider, StateProviderFactory, + providers::{BlockchainProvider, BlockchainProvider2}, + BlockReader, DatabaseProviderFactory, HeaderProvider, StateProviderFactory, }; use std::{path::PathBuf, process}; use tokio::task; -use tracing::error; +use tracing::{error, info, warn}; // Prefer jemalloc for performance reasons. #[cfg(all(feature = "jemalloc", unix))] @@ -28,57 +37,82 @@ pub struct ExtraArgs { /// Path of the rbuilder config to use #[arg(long = "rbuilder.config")] pub rbuilder_config: PathBuf, - /// Enable the engine2 experimental features on reth binary + + /// Enable the experimental engine features on reth binary + /// + /// DEPRECATED: experimental engine is default now, use --engine.legacy to enable the legacy + /// functionality #[arg(long = "engine.experimental", default_value = "false")] pub experimental: bool, + + /// Enable the legacy engine on reth binary + #[arg(long = "engine.legacy", default_value = "false")] + pub legacy: bool, + + /// Configure persistence threshold for engine experimental. + #[arg(long = "engine.persistence-threshold", conflicts_with = "legacy", default_value_t = DEFAULT_PERSISTENCE_THRESHOLD)] + pub persistence_threshold: u64, + + /// Configure the target number of blocks to keep in memory. + #[arg(long = "engine.memory-block-buffer-target", conflicts_with = "legacy", default_value_t = DEFAULT_MEMORY_BLOCK_BUFFER_TARGET)] + pub memory_block_buffer_target: u64, } fn main() { - use clap::Parser; - use reth::cli::Cli; - use reth_node_builder::EngineNodeLauncher; - use reth_node_ethereum::{node::EthereumAddOns, EthereumNode}; - use reth_provider::providers::BlockchainProvider2; - reth_cli_util::sigsegv_handler::install(); - if let Err(err) = Cli::::parse().run(|builder, extra_args| async move { - let enable_engine2 = extra_args.experimental; - match enable_engine2 { - true => { - let handle = builder - .with_types_and_provider::>() - .with_components(EthereumNode::components()) - .with_add_ons::() - .on_rpc_started(move |ctx, _| { - spawn_rbuilder(ctx.provider().clone(), extra_args.rbuilder_config); - Ok(()) - }) - .launch_with_fn(|builder| { - let launcher = EngineNodeLauncher::new( - builder.task_executor().clone(), - builder.config().datadir(), - ); - builder.launch_with(launcher) - }) - .await?; - handle.node_exit_future.await + // Enable backtraces unless a RUST_BACKTRACE value has already been explicitly provided. + if std::env::var_os("RUST_BACKTRACE").is_none() { + std::env::set_var("RUST_BACKTRACE", "1"); + } + + if let Err(err) = + Cli::::parse().run(|builder, extra_args| async move { + if extra_args.experimental { + warn!(target: "reth::cli", "Experimental engine is default now, and the --engine.experimental flag is deprecated. To enable the legacy functionality, use --engine.legacy."); } - false => { - let handle = builder - .with_types_and_provider::>() - .with_components(EthereumNode::components()) - .with_add_ons::() - .on_rpc_started(move |ctx, _| { - spawn_rbuilder(ctx.provider().clone(), extra_args.rbuilder_config); - Ok(()) - }) - .launch() - .await?; - handle.node_exit_future.await + + let use_legacy_engine = extra_args.legacy; + match use_legacy_engine { + false => { + let engine_tree_config = TreeConfig::default() + .with_persistence_threshold(extra_args.persistence_threshold) + .with_memory_block_buffer_target(extra_args.memory_block_buffer_target); + let handle = builder + .with_types_and_provider::>() + .with_components(EthereumNode::components()) + .with_add_ons(EthereumAddOns::default()) + .on_rpc_started(move |ctx, _| { + spawn_rbuilder(ctx.provider().clone(), extra_args.rbuilder_config); + Ok(()) + }) + .launch_with_fn(|builder| { + let launcher = EngineNodeLauncher::new( + builder.task_executor().clone(), + builder.config().datadir(), + engine_tree_config, + ); + builder.launch_with(launcher) + }) + .await?; + handle.node_exit_future.await + } + true => { + info!(target: "reth::cli", "Running with legacy engine"); + let handle = builder + .with_types_and_provider::>() + .with_components(EthereumNode::components()) + .with_add_ons::>(Default::default()) + .on_rpc_started(move |ctx, _| { + spawn_rbuilder(ctx.provider().clone(), extra_args.rbuilder_config); + Ok(()) + }) + .launch().await?; + handle.node_exit_future.await + } } - } - }) { + }) + { eprintln!("Error: {err:?}"); std::process::exit(1); } @@ -90,7 +124,11 @@ fn main() { fn spawn_rbuilder(provider: P, config_path: PathBuf) where DB: Database + Clone + 'static, - P: DatabaseProviderFactory + StateProviderFactory + HeaderProvider + Clone + 'static, + P: DatabaseProviderFactory + + StateProviderFactory + + HeaderProvider + + Clone + + 'static, { let _handle = task::spawn(async move { let result = async { diff --git a/crates/transaction-pool-bundle-ext/Cargo.toml b/crates/transaction-pool-bundle-ext/Cargo.toml index 9106b7aa..ef22b78c 100644 --- a/crates/transaction-pool-bundle-ext/Cargo.toml +++ b/crates/transaction-pool-bundle-ext/Cargo.toml @@ -7,8 +7,13 @@ edition.workspace = true reth = { workspace = true } reth-eth-wire-types = { workspace = true } reth-primitives = { workspace = true } -reth-rpc-types = { workspace = true } reth-transaction-pool = { workspace = true } +alloy-primitives = { version = "0.8.9", default-features = false } +alloy-rpc-types-beacon = { version = "0.5.4", features = [ + "ssz", +] } +alloy-eips = { version = "0.5.4" } + tokio = { workspace = true } diff --git a/crates/transaction-pool-bundle-ext/bundle_pool_ops/rbuilder/Cargo.toml b/crates/transaction-pool-bundle-ext/bundle_pool_ops/rbuilder/Cargo.toml index ae059f56..7618b468 100644 --- a/crates/transaction-pool-bundle-ext/bundle_pool_ops/rbuilder/Cargo.toml +++ b/crates/transaction-pool-bundle-ext/bundle_pool_ops/rbuilder/Cargo.toml @@ -7,10 +7,11 @@ edition = "2021" transaction-pool-bundle-ext = { path = "../.." } rbuilder = { path = "../../../rbuilder" } +alloy-primitives.workspace = true +alloy-rpc-types-beacon.workspace = true reth-primitives = { workspace = true } reth-provider = { workspace = true } reth-db-api = { workspace = true } -reth-rpc-types = { workspace = true } derive_more = { workspace = true } eyre = { workspace = true } @@ -20,8 +21,8 @@ tracing = { workspace = true } [features] optimism = [ - "reth-primitives/optimism", "rbuilder/optimism", - "reth-provider/optimism", - "reth-db-api/optimism" + "reth-db-api/optimism", + "reth-primitives/optimism", + "reth-provider/optimism" ] diff --git a/crates/transaction-pool-bundle-ext/bundle_pool_ops/rbuilder/src/lib.rs b/crates/transaction-pool-bundle-ext/bundle_pool_ops/rbuilder/src/lib.rs index cbca555f..0cdff24e 100644 --- a/crates/transaction-pool-bundle-ext/bundle_pool_ops/rbuilder/src/lib.rs +++ b/crates/transaction-pool-bundle-ext/bundle_pool_ops/rbuilder/src/lib.rs @@ -6,6 +6,8 @@ use core::fmt; use std::{fmt::Formatter, path::Path, sync::Arc, time::Duration}; +use alloy_primitives::U256; +use alloy_rpc_types_beacon::events::PayloadAttributesEvent; use derive_more::From; use rbuilder::live_builder::cli::LiveBuilderConfig; use rbuilder::{ @@ -27,9 +29,8 @@ use rbuilder::{ telemetry, }; use reth_db_api::Database; -use reth_primitives::{TransactionSigned, U256}; -use reth_provider::{DatabaseProviderFactory, HeaderProvider, StateProviderFactory}; -use reth_rpc_types::beacon::events::PayloadAttributesEvent; +use reth_primitives::TransactionSigned; +use reth_provider::{BlockReader, DatabaseProviderFactory, HeaderProvider, StateProviderFactory}; use tokio::{ sync::{ mpsc::{self, error::SendError}, @@ -94,7 +95,11 @@ impl BundlePoolOps { ) -> Result where DB: Database + Clone + 'static, - P: DatabaseProviderFactory + StateProviderFactory + HeaderProvider + Clone + 'static, + P: DatabaseProviderFactory + + StateProviderFactory + + HeaderProvider + + Clone + + 'static, { // Create the payload source to trigger new block building let cancellation_token = CancellationToken::new(); @@ -126,7 +131,6 @@ impl BundlePoolOps { let builders = create_builders( vec![builder_strategy], config.base_config.live_root_hash_config().unwrap(), - config.base_config.root_hash_task_pool().unwrap(), config.base_config.sbundle_mergeabe_signers(), ); diff --git a/crates/transaction-pool-bundle-ext/src/bundle_supported_pool.rs b/crates/transaction-pool-bundle-ext/src/bundle_supported_pool.rs index 59efcd4f..d956fc16 100644 --- a/crates/transaction-pool-bundle-ext/src/bundle_supported_pool.rs +++ b/crates/transaction-pool-bundle-ext/src/bundle_supported_pool.rs @@ -1,16 +1,18 @@ //! Houses [`BundleSupportedPool`]. +use alloy_eips::eip4844::{BlobAndProofV1, BlobTransactionSidecar}; +use alloy_primitives::{Address, TxHash, B256, U256}; +use alloy_rpc_types_beacon::events::PayloadAttributesEvent; use reth::providers::ChangedAccount; use reth_eth_wire_types::HandleMempoolData; -use reth_primitives::{Address, PooledTransactionsElement, TxHash, U256}; -use reth_rpc_types::{beacon::events::PayloadAttributesEvent, BlobTransactionSidecar}; +use reth_primitives::PooledTransactionsElement; use reth_transaction_pool::{ AllPoolTransactions, AllTransactionsEvents, BestTransactions, BestTransactionsAttributes, - BlobStore, BlobStoreError, BlockInfo, CanonicalStateUpdate, GetPooledTransactionLimit, - NewBlobSidecar, NewTransactionEvent, Pool, PoolConfig, PoolResult, PoolSize, - PropagatedTransactions, TransactionEvents, TransactionListenerKind, TransactionOrdering, - TransactionOrigin, TransactionPool, TransactionPoolExt as TransactionPoolBlockInfoExt, - TransactionValidator, ValidPoolTransaction, + BlobStore, BlobStoreError, BlockInfo, CanonicalStateUpdate, EthPoolTransaction, + GetPooledTransactionLimit, NewBlobSidecar, NewTransactionEvent, Pool, PoolConfig, PoolResult, + PoolSize, PropagatedTransactions, TransactionEvents, TransactionListenerKind, + TransactionOrdering, TransactionOrigin, TransactionPool, + TransactionPoolExt as TransactionPoolBlockInfoExt, TransactionValidator, ValidPoolTransaction, }; use std::{collections::HashSet, future::Future, sync::Arc}; use tokio::sync::mpsc::Receiver; @@ -110,7 +112,7 @@ impl Clone for BundleSupportedPool /// TODO: Use a crate like `delegate!` or `ambassador` to automate this. impl TransactionPool for BundleSupportedPool where - V: TransactionValidator, + V: TransactionValidator, T: TransactionOrdering::Transaction>, S: BlobStore, B: BundlePoolOperations, @@ -219,14 +221,6 @@ where self.tx_pool.best_transactions() } - #[allow(deprecated)] - fn best_transactions_with_base_fee( - &self, - base_fee: u64, - ) -> Box>>> { - self.tx_pool.best_transactions_with_base_fee(base_fee) - } - fn best_transactions_with_attributes( &self, best_transactions_attributes: BestTransactionsAttributes, @@ -300,23 +294,86 @@ where self.tx_pool.unique_senders() } - fn get_blob(&self, tx_hash: TxHash) -> Result, BlobStoreError> { + fn get_blob( + &self, + tx_hash: TxHash, + ) -> Result>, BlobStoreError> { self.tx_pool.get_blob(tx_hash) } fn get_all_blobs( &self, tx_hashes: Vec, - ) -> Result, BlobStoreError> { + ) -> Result)>, BlobStoreError> { self.tx_pool.get_all_blobs(tx_hashes) } fn get_all_blobs_exact( &self, tx_hashes: Vec, - ) -> Result, BlobStoreError> { + ) -> Result>, BlobStoreError> { self.tx_pool.get_all_blobs_exact(tx_hashes) } + + fn remove_transactions_and_descendants( + &self, + hashes: Vec, + ) -> Vec>> { + self.tx_pool.remove_transactions_and_descendants(hashes) + } + + fn remove_transactions_by_sender( + &self, + sender: Address, + ) -> Vec>> { + self.tx_pool.remove_transactions_by_sender(sender) + } + + fn get_pending_transactions_with_predicate( + &self, + predicate: impl FnMut(&ValidPoolTransaction) -> bool, + ) -> Vec>> { + self.tx_pool + .get_pending_transactions_with_predicate(predicate) + } + + fn get_pending_transactions_by_sender( + &self, + sender: Address, + ) -> Vec>> { + self.tx_pool.get_pending_transactions_by_sender(sender) + } + + fn get_queued_transactions_by_sender( + &self, + sender: Address, + ) -> Vec>> { + self.tx_pool.get_queued_transactions_by_sender(sender) + } + + fn get_highest_transaction_by_sender( + &self, + sender: Address, + ) -> Option>> { + self.tx_pool.get_highest_transaction_by_sender(sender) + } + + fn get_highest_consecutive_transaction_by_sender( + &self, + sender: Address, + on_chain_nonce: u64, + ) -> Option>> { + self.tx_pool + .get_highest_consecutive_transaction_by_sender(sender, on_chain_nonce) + } + + fn get_blobs_for_versioned_hashes( + &self, + versioned_hashes: &[B256], + ) -> Result>, BlobStoreError> { + self.tx_pool + .get_blobs_for_versioned_hashes(versioned_hashes) + } } /// Implements the [`BundlePoolOperations`] interface by delegating to the inner `bundle_pool`. @@ -369,7 +426,7 @@ where // [`BundlePoolOperations`] implemented, it can implement [`TransactionPoolBundleExt`]. impl TransactionPoolBundleExt for BundleSupportedPool where - V: TransactionValidator, + V: TransactionValidator, T: TransactionOrdering::Transaction>, S: BlobStore, B: BundlePoolOperations, @@ -379,7 +436,7 @@ where /// [`TransactionPool`] often requires implementing the block info extension. impl TransactionPoolBlockInfoExt for BundleSupportedPool where - V: TransactionValidator, + V: TransactionValidator, T: TransactionOrdering::Transaction>, S: BlobStore, B: BundlePoolOperations, diff --git a/crates/transaction-pool-bundle-ext/src/traits.rs b/crates/transaction-pool-bundle-ext/src/traits.rs index 1d21d0b4..1a68bc30 100644 --- a/crates/transaction-pool-bundle-ext/src/traits.rs +++ b/crates/transaction-pool-bundle-ext/src/traits.rs @@ -1,7 +1,7 @@ //! [`TransactionPoolBundleExt`] implementation generic over any bundle and network type. -use reth_primitives::U256; -use reth_rpc_types::beacon::events::PayloadAttributesEvent; +use alloy_primitives::U256; +use alloy_rpc_types_beacon::events::PayloadAttributesEvent; use reth_transaction_pool::TransactionPool; use std::{fmt::Debug, future::Future}; From 9919c153fdeb6922e7ae8d67b8b5a36c5c6ca8dc Mon Sep 17 00:00:00 2001 From: Barnabas Busa Date: Fri, 29 Nov 2024 08:22:07 +0100 Subject: [PATCH 06/30] fix: bump rust version in Dockerfile (#257) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At the latest builds I’m seeing the following errror: ``` builder 3/8] RUN --mount=type=cache,target=/sccache,sharing=locked cargo chef cook --release --recipe-path recipe.json: 24.80 reth-trie-common@1.1.1 requires rustc 1.82 24.80 reth-trie-db@1.1.1 requires rustc 1.82 24.80 reth-trie-parallel@1.1.1 requires rustc 1.82 24.80 Either upgrade rustc or select compatible dependency versions with 24.80 `cargo update @ --precise ` 24.80 where `` is the latest version supporting rustc 1.81.0 24.80 24.83 thread 'main' panicked at /usr/local/cargo/registry/src/index.crates.io-6f17d22bba15001f/cargo-chef-0.1.68/src/recipe.rs:218:27: 24.83 Exited with status code: 101 24.83 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace ------ Dockerfile:52 ``` --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index bccd818e..a5749ba5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,7 +6,7 @@ # # Based on https://depot.dev/blog/rust-dockerfile-best-practices # -FROM rust:1.81 as base +FROM rust:1.82 as base ARG FEATURES From 1e36b9607eff145fa5232ef41046b9ddad440a97 Mon Sep 17 00:00:00 2001 From: Chris Hager Date: Fri, 29 Nov 2024 11:27:53 +0100 Subject: [PATCH 07/30] Update CODEOWNERS (#259) --- .github/CODEOWNERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 5082eca0..04b12c63 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,5 +1,5 @@ # These owners will be the default owners for everything in # the repo. Unless a later match takes precedence, # they will be requested for review when someone opens a pull request. -* @dvush @ZanCorDX @metachris @jakubhruby7 @ferranbt -/crates/ @dvush @ZanCorDX @ferranbt +* @dvush @ZanCorDX @ferranbt @liamaharon @metachris +/crates/ @dvush @ZanCorDX @ferranbt @liamaharon From a43f1b4d4e29517ad144324c0a102472f3089dcc Mon Sep 17 00:00:00 2001 From: ZanCorDX <126988525+ZanCorDX@users.noreply.github.com> Date: Fri, 29 Nov 2024 08:17:59 -0300 Subject: [PATCH 08/30] Improve docs (#239) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 📝 Summary High-level doc about LiveBuilder. ## 💡 Motivation and Context - It was really hard to understand the whole system from scratch. - I'm so nice that I love making docs for the comunity. - I had a fight with my wife and I needed an excuse to stay a few more hours at the office. ## ✅ I have completed the following steps: * [ ] Run `make lint` * [ ] Run `make test` * [ ] Added tests (if applicable) --- docs/LIVEBUILDER_DATAFLOW.md | 182 +++++++++++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100644 docs/LIVEBUILDER_DATAFLOW.md diff --git a/docs/LIVEBUILDER_DATAFLOW.md b/docs/LIVEBUILDER_DATAFLOW.md new file mode 100644 index 00000000..819dd671 --- /dev/null +++ b/docs/LIVEBUILDER_DATAFLOW.md @@ -0,0 +1,182 @@ +# LiveBuilder Dataflow + +The [`LiveBuilder`](../crates/rbuilder/src/live_builder/mod.rs) struct is the main component of rbuilder. + +## Core Components + +To create a `LiveBuilder` instance, you need the following core components: + +1. [`blocks_source`](../crates/rbuilder/src/live_builder/mod.rs): The source of slots to build. Implements the [`SlotSource`](../crates/rbuilder/src/live_builder/mod.rs) trait. This abstraction enables rbuilder to handle block building in various contexts: + - L1: Consensus client generating slots with potential forks + - L2: Sequencer generating slots + +2. [`builders`](../crates/rbuilder/src/live_builder/mod.rs): A vector of objects implementing the [`BlockBuildingAlgorithm`](../crates/rbuilder/src/building/builders/mod.rs) trait. Each builder: + - Takes a base block state and a stream of simulated orders + - Continuously generates new blocks + - Optimizes to maximize the true block value + +3. [`sink_factory`](../crates/rbuilder/src/live_builder/mod.rs): A factory for the destination of built blocks. Implements [`UnfinishedBlockBuildingSinkFactory`](../crates/rbuilder/src/building/builders/mod.rs). This abstraction supports different contexts: + - L1: Requires bidding + - L2: No bidding needed + - Testing environments + +## Initialization Process + +The main entrypoint `LiveBuilder::run()` initializes several long-lived components: + +- **[RPC Module](../crates/rbuilder/src/live_builder/order_input/rpc_server.rs)**: + - Listens for RPC calls (primarily order flow input) + - Pushes received data to a channel + +- **[OrderPool](../crates/rbuilder/src/live_builder/order_input/orderpool.rs)**: + - Receives RPC commands (order flow) + - Receives mempool txs + - Stores orders in memory + - Provides subscription mechanism for block orders + +- **[OrderSimulationPool](../crates/rbuilder/src/live_builder/simulation/mod.rs)**: + - Manages a pool of threads ready for order simulation + - Handles concurrent order simulations + +- **[BlockBuildingPool](../crates/rbuilder/src/live_builder/building/mod.rs)**: + - Aggregates multiple components: + - OrderPool + - OrderSimulationPool + - LiveBuilder::sink_factory + - LiveBuilder::builders + - Triggers block building tasks + +- **payload_events_channel**: + - A channel of [`MevBoostSlotData`](../crates/rbuilder/src/live_builder/payload_events/mod.rs) + - Receives block-building opportunities + - Each received `MevBoostSlotData` triggers a new block-building task via `BlockBuildingPool` + - Sources slots from `LiveBuilder::blocks_source` + +- **Dataflow Diagram** + + +```mermaid + graph LR; + MainThread-- polls -->payload_events_channel + payload_events_channel + MainThread("🔄Main thread") + RPC + RPC--eth_sendBundle-->Ch1 + RPC--mev_sendBundle-->Ch1 + RPC--eth_cancelBundle-->Ch1 + RPC--eth_sendRawTransaction-->Ch1 + MemPool("Mempool
(reth connection)")--new txs-->Ch1 + Ch1("channel") + OrderPool("**OrderPool**") + Ch1<-- "🔄polling" -->OrderPool + BlockBuildingPool("**BlockBuildingPool**") + OrderSimulationPool("**OrderSimulationPool**") + + sink_factory + BlockBuildingPool-- owns -->B1 + BlockBuildingPool-- owns -->BN + BlockBuildingPool-- owns -->sink_factory + BlockBuildingPool-- owns -->OrderSimulationPool + BlockBuildingPool-- "ref via **OrderPoolSubscriber**" -->OrderPool + MainThread-- triggers building task-->BlockBuildingPool + subgraph builders + B1[Builder 1] + BN[Builder N] + B1 -.- BN + end +``` + +## Block building +Although this stage is referred to as "building," it doesn't completely build the blocks - it only fills them with transactions to extract as much MEV as possible. + +The block building process begins with a flow of `ReplaceableOrderPoolCommand`s arriving from the `OrderPool` (subscribed via an OrderPoolSubscriber). These operations can be: +- Adding a new order (`ReplaceableOrderPoolCommand::Order`) +- Replacing an existing order (`ReplaceableOrderPoolCommand::Order` for an existing uuid) +- Canceling an order (`ReplaceableOrderPoolCommand::CancelBundle`/`ReplaceableOrderPoolCommand::CancelShareBundle`) + +Throughout the order pipeline, we consistently use these commands instead of plain `Orders` since the entire pipeline must handle updates and cancellations. + +As mentioned before, the `BlockBuildingPool` initiates the block building task (`BlockBuildingPool::start_block_building`) which involves the following connections: +- An [OrderReplacementManager](../crates/rbuilder/src/live_builder/order_input/order_replacement_manager.rs) is created and set as the sink for the block's order flow (`OrderPoolSubscriber::add_sink`). The `OrderReplacementManager` has 2 main responsibilities: + + - Update/Cancellation handling: The `OrderReplacementManager` transforms all cancellations and updates into add/remove operations. From this point downstream, the system is not aware of updates/cancellations. + - Sequence correction: Cancellations and updates have a sequence number. Due to external simulation timings, these operations might arrive out of order. `OrderReplacementManager` ensures that the operation with the largest sequence number is always used. +- To adapt the push nature of `OrderReplacementManager` to the pull nature of the simulation stage, an [OrdersForBlock](../crates/rbuilder/src/live_builder/order_input/orderpool.rs) is inserted. It simply pushes order operations on a channel for the simulation to poll. +- A simulation task is spawned via `OrderSimulationPool::spawn_simulation_job` taking the above-mentioned channel as input. Simulations are performed using the threads created on `OrderSimulationPool::new`. The output of the simulations is pushed to a channel (inside `SlotOrderSimResults`) of `SimulatedOrderCommand`. Note that the simulation stage also propagates cancellations. + +- A destination for the generated blocks (`UnfinishedBlockBuildingSink`) is created from `BlockBuildingPool::sink_factory` via `UnfinishedBlockBuildingSinkFactory::create_sink`. +- To multiplex from the single-receiver simulations channel to the multiple destinations (builders), a broadcast channel is created along with a forwarding task. +- One new task is spawned for each `BlockBuildingAlgorithm` in `BlockBuildingPool::builders`. The same `UnfinishedBlockBuildingSink` created above is used as the sink for all building algorithms. +- An extra task is spawned to prefetch data to speed up root hash calculations (`run_trie_prefetcher`). + +The output of this stage consists of filled blocks (`BlockBuildingHelper`) which can still be upgraded and usually need the final payout transaction to the validator to be added. These blocks also need to be sealed, which mainly involves computing the root hash of the final state—an expensive operation that we only want to perform at the last moment when we know we are going to bid with the block. + +Note that at this point we remain network agnostic; the result could be used for either L1 or L2. + +```mermaid +graph LR + + OrderPool("**OrderPool**") + OrderReplacementManager("**OrderReplacementManager**") + OrderChannel("channel") + SimulationTask("🔄 Simulation task") + + OrderPool-- replaceable orders -->OrderReplacementManager + OrderReplacementManager-- orders -->OrderChannel + SimulationTask-- polls -->OrderChannel + SimulationTask-- simulation request -->OrderSimulationPool + OrderSimulationPool("**OrderSimulationPool**
Several sim threads 🔄🔄🔄") + OrderSimulationPool-- simulation result -->SimulationTask + SimChannel("channel") + SimulationTask-- simulated orders -->SimChannel + SimChannel<-- "🔄polling" -->BrSimChannel + BrSimChannel("broadcast
channel") + B1("🔄building task 1") + BN("🔄building task N") + B1 -.- BN + + B1--polls-->BrSimChannel + BN--polls-->BrSimChannel + run_trie_prefetcher("🔄**run_trie_prefetcher**") + run_trie_prefetcher--polls-->BrSimChannel +``` + +## Block sealing and bidding (specific for L1 bidding) + +Once the blocks are filled with orders, they are ready to be used as bids. +The only remaining steps are deciding how much to bid for each block (or sometimes discard them) and then seal them (insert final payout tx and compute the root hash). + +Each block has a `true block value`, which is the amount of MEV the block is generating and the maximum bid we can make. +If we bid 0, then we'll try to make the maximum amount of profit (`true block value`). If we bid `true block value`, we will make no profit at all. We can even bid above `true block value`, in which case we will subsidize the block out of our pocket, losing money. + +To achieve this, the provided rbuilder example uses the [BlockSealingBidderFactory](../crates/rbuilder/src/live_builder/block_output/block_sealing_bidder_factory.rs) as its `UnfinishedBlockBuildingSinkFactory`. You can check its creation in `LiveBuilderConfig::new_builder`, but this is just one of many possible ways to create your own `LiveBuilder`. + +On creation, the `BlockSealingBidderFactory` receives: +- [BiddingService](../crates/rbuilder/src/live_builder/block_output/bidding/interfaces.rs) (trait): Factory for each block's [SlotBidder](../crates/rbuilder/src/live_builder/block_output/bidding/interfaces.rs). The `SlotBidder` (trait) is the object in charge of receiving all the blocks and the bid values the competition makes and placing the bids. +As extra information for the bidding process, the `BiddingService` is constantly fed with landed blocks info which can be used to check things like our inclusion ratio, landed subsidies, etc. +- [BuilderSinkFactory](../crates/rbuilder/src/live_builder/block_output/relay_submit.rs) (trait): This factory creates the final destination of our bids, the [BlockBuildingSink](../crates/rbuilder/src/live_builder/block_output/relay_submit.rs). Bids end in the form of final [Block](crates/rbuilder/src/building/builders/mod.rs)s which are ready to be submitted to the relays. In our particular case, we use a [RelaySubmitSinkFactory](../crates/rbuilder/src/live_builder/block_output/relay_submit.rs) as our `BuilderSinkFactory`, but we could use any other sink (e.g., some dummy `BuilderSinkFactory` for testing). +- [BidValueSource](../crates/rbuilder/src/live_builder/block_output/bid_value_source/interfaces.rs) (trait): This object allows us to get a feed of what the competition is bidding, which is important information for placing our own bids. It works via a subscription mechanism through the trait [BidValueObs](../crates/rbuilder/src/live_builder/block_output/bid_value_source/interfaces.rs). +- [WalletBalanceWatcher](../crates/rbuilder/src/live_builder/block_output/bidding/wallet_balance_watcher.rs): Object to handle landed block information that we need to feed to the `BiddingService`. + +On each block `BlockSealingBidderFactory` creates the following `BlockSealingBidder` (some intermediate connecting objects were omitted for simplicity): + +```mermaid + graph LR; + Source("🔄Blocks from
previous stage")-->SlotBidder + BiddingService("**BiddingService**") + subgraph BlockSealingBidder + SlotBidder("**SlotBidder**
could use a
spawned task") + SlotBidder-."accesses internal
bidding info".->BiddingService + BidValueSource("🔄**BidValueSource**")--bids from the
competition-->SlotBidder + SlotBidder--"send_bid"-->Sealer("🔄**BidMaker** (Sealer)") + Sealer--"new_block"-->BlockBuildingSink("**BlockBuildingSink**
🔄Task submitting to the relays") + end +``` +The [BidMaker](../src/block_descriptor_bidding/traits.rs) is in charge of sealing the block, that is, adding the final payout tx to the validator and computing the root hash. Depending on `BlockSealingBidderFactory`'s configuration, it can use [SequentialSealerBidMaker](../crates/rbuilder/src/live_builder/block_output/bidding/sequential_sealer_bid_maker.rs) or [ParallelSealerBidMaker](../crates/rbuilder/src/live_builder/block_output/bidding/parallel_sealer_bid_maker.rs). + +Some notes on the provided rbuilder example: +- The provided implementation of `BiddingService` is [TrueBlockValueBiddingService](../crates/rbuilder/src/live_builder/block_output/bidding/true_block_value_bidder.rs). This is a dummy service whose created `SlotBidder`s bid all true block value. +- No real `BidValueSource` is provided; we use a [NullBidValueSource](../crates/rbuilder/src/live_builder/block_output/bid_value_source/null_bid_value_source.rs) which never notifies anything. + +These 2 objects should be implemented to have a real competitive builder. + From f25fab356ab14a6a7f583d3096c48915bdebfa0c Mon Sep 17 00:00:00 2001 From: Vitaly Drogan Date: Fri, 29 Nov 2024 17:54:09 +0100 Subject: [PATCH 09/30] Fix Bundle data deserialisation (#256) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 📝 Summary ## 💡 Motivation and Context --- ## ✅ I have completed the following steps: * [x] Run `make lint` * [x] Run `make test` * [x] Added tests (if applicable) --------- Co-authored-by: Daniel Xifra Co-authored-by: Ferran Borreguero --- crates/rbuilder/src/primitives/serialize.rs | 68 ++++++++++++++++++++- 1 file changed, 65 insertions(+), 3 deletions(-) diff --git a/crates/rbuilder/src/primitives/serialize.rs b/crates/rbuilder/src/primitives/serialize.rs index 0260d8b7..df621965 100644 --- a/crates/rbuilder/src/primitives/serialize.rs +++ b/crates/rbuilder/src/primitives/serialize.rs @@ -5,8 +5,8 @@ use super::{ TransactionSignedEcRecoveredWithBlobs, TxRevertBehavior, }; use alloy_primitives::{Address, Bytes, B256, U64}; -use serde::{Deserialize, Serialize}; -use serde_with::{serde_as, DefaultOnNull}; +use serde::{Deserialize, Deserializer, Serialize}; +use serde_with::serde_as; use thiserror::Error; use tracing::error; use uuid::Uuid; @@ -36,6 +36,15 @@ impl TxEncoding { } } +fn deserialize_vec_b256_from_null_or_string<'de, D>(deserializer: D) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + // Option::deserialize handles null.S + let opt = Option::deserialize(deserializer)?; + Ok(opt.unwrap_or_default()) +} + /// Struct to de/serialize json Bundles from bundles APIs and from/db. /// Does not assume a particular format on txs. #[serde_as] @@ -44,7 +53,7 @@ impl TxEncoding { pub struct RawBundle { pub block_number: U64, pub txs: Vec, - #[serde_as(deserialize_as = "DefaultOnNull")] + #[serde(default, deserialize_with = "deserialize_vec_b256_from_null_or_string")] pub reverting_tx_hashes: Vec, #[serde(skip_serializing_if = "Option::is_none")] pub replacement_uuid: Option, @@ -665,6 +674,59 @@ mod tests { assert_eq!(bundle.uuid, uuid!("5d5bf52c-ac3f-57eb-a3e9-fc01b18ca516")); } + #[test] + fn test_correct_bundle_uuid_missing_reverting_hashes() { + // raw json string + let bundle_json = r#" + { + "blockNumber": "0xA136F1F", + "txs": ["0x02f9037b018203cd8405f5e1008503692da370830388ba943fc91a3afd70395cd496c647d5a6cc9d4b2b7fad8780e531581b77c4b903043593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000064f390d300000000000000000000000000000000000000000000000000000000000000030b090c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000080e531581b77c400000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000009184e72a0000000000000000000000000000000000000000000000000000080e531581b77c400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000b5ea574dd8f2b735424dfc8c4e16760fc44a931b000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000c001a0a9ea84ad107d335afd5e5d2ddcc576f183be37386a9ac6c9d4469d0329c22e87a06a51ea5a0809f43bf72d0156f1db956da3a9f3da24b590b7eed01128ff84a2c1"] + }"#; + + let bundle_request: RawBundle = + serde_json::from_str(bundle_json).expect("failed to decode bundle"); + + let bundle = bundle_request + .try_into(TxEncoding::WithBlobData) + .expect("failed to convert bundle request to bundle"); + + assert_eq!( + bundle.hash, + fixed_bytes!("cf3c567aede099e5455207ed81c4884f72a4c0c24ddca331163a335525cd22cc") + ); + assert_eq!(bundle.uuid, uuid!("5d5bf52c-ac3f-57eb-a3e9-fc01b18ca516")); + } + + ///Real life case + #[test] + fn test_correct_bundle_uuid_null_reverting_hashes() { + // raw json string + let bundle_json ="{\"txs\":[\"0x02f901c00182123184cd0a3c00850d8c3ac83483186a00949f51040aec194a89cb6a7e852e79ea07cc0bf6488203abb9014e524f05aadf99a0839818b3f120ebac9b73f82b617dc6a5550000000000000004aa7fdb4059a9fc0400000000000000000000000000000000000000000000000000000000000000000000000000540101d99034942c4a883ff3ed6cda6c91fe505a58eb2e0000000000000001270250af8569d4ff712aaebc2f5971a824249fa7000000000000030015153da0e9e13cfc167b3d417d3721bf545479bb000bb800003c00540101d99034942c4a883ff3ed6cda6c91fe505a58eb2e00000000000000015533b61d314f7faf87df530de362f457a342ec1e00000000000003008107fca5494375fc743a9fc4d4844353a1af3d94000bb800003c00540101d99034942c4a883ff3ed6cda6c91fe505a58eb2e0000000000000001b81ab4b74522a25525e583f94dba73521cc4d56b0000000000000100308c6fbd6a14881af333649f17f2fde9cd75e2a6000000000000c080a061a306a26e0a66973364614912553f32c7915e899b188164bf2e99b97e08d0e8a00c76b844dc4b72c2040f14e69f0f9c3fa290a2db7c4a245d045155090ec7d746\"],\"replacementUuid\":null,\"signingAddress\":\"0x564d55a3a73f6efb907afe92b1706602b2d54018\",\"blockNumber\":\"0x142dd19\",\"minTimestamp\":null,\"maxTimestamp\":null,\"revertingTxHashes\":null}"; + + let bundle_request: RawBundle = + serde_json::from_str(bundle_json).expect("failed to decode bundle"); + + let bundle = bundle_request + .clone() + .try_into(TxEncoding::WithBlobData) + .expect("failed to convert bundle request to bundle"); + + let bundle_roundtrip = RawBundle::encode_no_blobs(bundle.clone()); + assert_eq!(bundle_request, bundle_roundtrip); + + assert_eq!( + bundle.hash, + fixed_bytes!("08b57aa2df6e4729c55b809d1110f16aba30956cfc17f7ad771441d6d418f991") + ); + assert_eq!(bundle.uuid, uuid!("0cc09d2b-6538-5d0e-a627-22c400845783")); + + assert!(bundle.reverting_tx_hashes.is_empty()); + assert_eq!(bundle.txs.len(), 1); + + assert_eq!(bundle.min_timestamp, None); + assert_eq!(bundle.max_timestamp, None); + } + #[test] fn test_correct_raw_tx_decoding() { // raw json string From 03f40b59079584ff6c67094a3733777dd8e2e0cc Mon Sep 17 00:00:00 2001 From: Ferran Borreguero Date: Fri, 29 Nov 2024 16:54:21 +0000 Subject: [PATCH 10/30] Add docker build step to CI (#258) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 📝 Summary This PR checks nightly in CI that the docker image can be built. --- ## ✅ I have completed the following steps: * [x] Run `make lint` * [x] Run `make test` * [x] Added tests (if applicable) --- .github/workflows/checks.yaml | 4 ++-- .github/workflows/checks_docker.yaml | 31 ++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/checks_docker.yaml diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index c09cbb8c..56bfc341 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -81,8 +81,8 @@ jobs: - name: Setup rust toolchain uses: dtolnay/rust-toolchain@stable with: - toolchain: ${{ matrix.toolchain }} - + toolchain: ${{ matrix.toolchain }} + - name: Download builder playground uses: flashbots/flashbots-toolchain@v0.1 with: diff --git a/.github/workflows/checks_docker.yaml b/.github/workflows/checks_docker.yaml new file mode 100644 index 00000000..7d9aa485 --- /dev/null +++ b/.github/workflows/checks_docker.yaml @@ -0,0 +1,31 @@ +name: Nightly Docker Build + +on: + schedule: + # Runs at 00:00 UTC every day + - cron: "0 0 * * *" + workflow_dispatch: # Allows manual triggering + +jobs: + build-docker: + name: Build Docker image + runs-on: warp-ubuntu-latest-x64-16x + + steps: + - name: Checkout sources + uses: actions/checkout@v4 + + - name: Docker QEMU + uses: docker/setup-qemu-action@v3 + + - name: Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Docker Build + uses: docker/build-push-action@v5 + with: + cache-from: type=gha + cache-to: type=gha,mode=max + platforms: linux/amd64 + context: . + push: false From af6f94ab6f97bea9ce19377c1df255d3b9b73004 Mon Sep 17 00:00:00 2001 From: liamaharon Date: Mon, 2 Dec 2024 12:21:48 +0400 Subject: [PATCH 11/30] Docker build time and CI (#261) Closes #260 Fixes Docker build time issue (now takes ~3m) and adds Docker build as a check in every PR. --- .github/workflows/checks_docker.yaml | 11 ++++++----- Dockerfile | 10 ++-------- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/.github/workflows/checks_docker.yaml b/.github/workflows/checks_docker.yaml index 7d9aa485..aa9dcb58 100644 --- a/.github/workflows/checks_docker.yaml +++ b/.github/workflows/checks_docker.yaml @@ -1,10 +1,11 @@ -name: Nightly Docker Build +name: Docker Build on: - schedule: - # Runs at 00:00 UTC every day - - cron: "0 0 * * *" - workflow_dispatch: # Allows manual triggering + workflow_dispatch: + pull_request: + merge_group: + push: + branches: [develop] jobs: build-docker: diff --git a/Dockerfile b/Dockerfile index a5749ba5..f6863939 100644 --- a/Dockerfile +++ b/Dockerfile @@ -26,10 +26,7 @@ ENV SCCACHE_DIR=/sccache FROM base AS planner WORKDIR /app -COPY ./Cargo.lock ./Cargo.lock -COPY ./Cargo.toml ./Cargo.toml -COPY ./.git ./.git -COPY ./crates/ ./crates/ +COPY . . RUN --mount=type=cache,target=/usr/local/cargo/registry \ --mount=type=cache,target=/usr/local/cargo/git \ @@ -49,10 +46,7 @@ COPY --from=planner /app/recipe.json recipe.json RUN --mount=type=cache,target=$SCCACHE_DIR,sharing=locked \ cargo chef cook --release --recipe-path recipe.json -COPY ./Cargo.lock ./Cargo.lock -COPY ./Cargo.toml ./Cargo.toml -COPY ./.git ./.git -COPY ./crates/ ./crates/ +COPY . . RUN --mount=type=cache,target=/usr/local/cargo/registry \ --mount=type=cache,target=/usr/local/cargo/git \ From 936c4ffc6e50b4f7fe6d9fb39de09ea054fa9107 Mon Sep 17 00:00:00 2001 From: sukoneck <19413126+sukoneck@users.noreply.github.com> Date: Tue, 3 Dec 2024 09:39:02 -0700 Subject: [PATCH 12/30] add `reth-rbuilder` as an artifact target in CI (#262) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 📝 Summary - add `reth-rbuilder` as an artifact target in the `release` workflow - run `build` job in `release` workflow inside container - add @sukoneck as codeowner for `/.github/` directory ## 💡 Motivation and Context 1. we need to store the binary for `reth-rbuilder` as an artifact. 2. while I was making these changes I ran into a dependency conflict with `GLIBC` so I included this change as well (happy to separate if needed). the downside of doing this, is that it doesn't work on macos runners, so I've disabled that for now. --- ## ✅ I have completed the following steps: successful run here https://github.com/flashbots/rbuilder/actions/runs/12130028687 --- .github/CODEOWNERS | 5 +- .github/workflows/release.yaml | 98 +++++++++++----------------------- 2 files changed, 35 insertions(+), 68 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 04b12c63..d4668950 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,5 +1,6 @@ # These owners will be the default owners for everything in # the repo. Unless a later match takes precedence, # they will be requested for review when someone opens a pull request. -* @dvush @ZanCorDX @ferranbt @liamaharon @metachris -/crates/ @dvush @ZanCorDX @ferranbt @liamaharon +* @dvush @ZanCorDX @ferranbt @liamaharon @metachris +/crates/ @dvush @ZanCorDX @ferranbt @liamaharon +/.github/ @dvush @ZanCorDX @ferranbt @liamaharon @metachris @sukoneck diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 49422ecd..ad985dee 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -23,10 +23,6 @@ on: default: false jobs: - # - # extract-version extracts the version from the tag or the branch name, - # for reuse in later jobs - # extract-version: name: Extract version runs-on: warp-ubuntu-latest-x64-16x @@ -55,14 +51,13 @@ jobs: echo "| \`GITHUB_SHA\` | \`${GITHUB_SHA}\` |" >> $GITHUB_STEP_SUMMARY echo "| \`VERSION\` | \`${VERSION}\` |" >> $GITHUB_STEP_SUMMARY - # - # build-binary builds a release binary for a variety of platforms - # build-binary: name: Build binary needs: extract-version if: ${{ github.event.inputs.build-binary == 'true' || github.event_name == 'push'}} # when manually triggered or version tagged runs-on: ${{ matrix.configs.runner }} + container: + image: ubuntu:22.04 env: VERSION: ${{ needs.extract-version.outputs.VERSION }} permissions: @@ -75,68 +70,47 @@ jobs: runner: warp-ubuntu-latest-x64-16x - target: aarch64-unknown-linux-gnu runner: warp-ubuntu-latest-arm64-16x - - target: aarch64-apple-darwin - runner: warp-macos-14-arm64-6x + # Paused until docker is pre-installed https://github.com/actions/runner-images/blob/main/images/macos/macos-14-arm64-Readme.md + # - target: aarch64-apple-darwin + # runner: warp-macos-14-arm64-6x features: - "" - - "redact_sensitive" + - "redact-sensitive" steps: - - name: Checkout sources - uses: actions/checkout@v4 - with: - fetch-depth: 0 # needed for built.rs to get GIT_HEAD_REF - - # https://github.com/dtolnay/rust-toolchain - - name: Setup rust toolchain - uses: dtolnay/rust-toolchain@stable - with: - target: ${{ matrix.configs.target }} - - # https://github.com/WarpBuilds/rust-cache - - name: Run WarpBuilds/rust-cache - uses: WarpBuilds/rust-cache@v2 - with: - cache-on-failure: true - - # https://github.com/Mozilla-Actions/sccache-action - - name: Setup sccache-action - uses: mozilla-actions/sccache-action@v0.0.5 - - - name: Set env vars + - name: Install dependencies run: | - echo "SCCACHE_GHA_ENABLED=true" >> $GITHUB_ENV - echo "RUSTC_WRAPPER=sccache" >> $GITHUB_ENV - - - name: Prepare output filename - run: | - if [ -z "${{ matrix.features }}" ]; then - OUTPUT_FILENAME="rbuilder-${VERSION}-${{ matrix.configs.target }}.tar.gz" - else - OUTPUT_FILENAME="rbuilder-${VERSION}-${{ matrix.configs.target }}-${{ matrix.features }}.tar.gz" - fi - echo "OUTPUT_FILENAME=$OUTPUT_FILENAME" >> $GITHUB_ENV - echo "Filename: ${OUTPUT_FILENAME}" + apt-get update + apt-get install -y \ + build-essential \ + curl \ + git \ + libclang-dev \ + libssl-dev \ + pkg-config \ + protobuf-compiler + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y + + - uses: actions/checkout@v4 # must install git before checkout and set safe.directory after checkout because of container - name: Build rbuilder binary - run: cargo build --release --features=${{ matrix.features }} - - - name: Prepare artifacts run: | - mkdir -p artifacts - tar -czf "artifacts/${OUTPUT_FILENAME}" -C target/release rbuilder + git config --global --add safe.directory "$(pwd)" + . $HOME/.cargo/env + cargo build --release --features=${{ matrix.features }} --target ${{ matrix.configs.target }} + + - name: Upload rbuilder artifact + uses: actions/upload-artifact@v4 + with: + name: rbuilder-${{ matrix.configs.target }}${{ matrix.features && '-' }}${{ matrix.features }} + path: target/${{ matrix.configs.target }}/release/rbuilder - # https://github.com/actions/upload-artifact - - name: Upload artifacts - uses: actions/upload-artifact@v4.3.1 + - name: Upload reth-rbuilder artifact + uses: actions/upload-artifact@v4 with: - name: ${{ env.OUTPUT_FILENAME }} - path: artifacts/${{ env.OUTPUT_FILENAME }} + name: reth-rbuilder-${{ matrix.configs.target }}${{ matrix.features && '-' }}${{ matrix.features }} + path: target/${{ matrix.configs.target }}/release/reth-rbuilder - # - # draft-release runs after building for various targets, collects artifacts and prepares a draft release - # (only when running against a tag!) - # draft-release: name: Draft release if: ${{ github.event.inputs.draft-release == 'true' || github.event_name == 'push'}} # when manually triggered or version tagged @@ -150,7 +124,6 @@ jobs: - name: Checkout uses: actions/checkout@v4 - # https://github.com/actions/download-artifact - name: Download artifacts uses: actions/download-artifact@v4 with: @@ -164,7 +137,6 @@ jobs: for file in *; do sha256sum "$file" >> sha256sums.txt; done; cat sha256sums.txt - # https://github.com/softprops/action-gh-release - name: Create release draft uses: softprops/action-gh-release@v2.0.5 id: create-release-draft @@ -181,12 +153,6 @@ jobs: echo "### Release Draft: ${{ env.VERSION }}" >> $GITHUB_STEP_SUMMARY echo "${{ steps.create-release-draft.outputs.url }}" >> $GITHUB_STEP_SUMMARY - # - # build-docker builds a Docker image and pushes it to the GitHub Container Registry at ghcr.io - # - # See also - # - https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry - # build-docker: if: ${{ github.event.inputs.build-docker == 'true' }} name: Build and publish Docker image From 921db00de2cc3926187aed876e2c021e2e5b474a Mon Sep 17 00:00:00 2001 From: Ferran Borreguero Date: Tue, 3 Dec 2024 21:05:36 +0000 Subject: [PATCH 13/30] Disable watchdog if watchdog_timeout_sec config is 0 (#263) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 📝 Summary This PR disables the watchdog if the value from config is zero. --- ## ✅ I have completed the following steps: * [x] Run `make lint` * [x] Run `make test` * [x] Added tests (if applicable) --- crates/rbuilder/src/bin/dummy-builder.rs | 2 +- crates/rbuilder/src/live_builder/base_config.rs | 12 ++++++++---- crates/rbuilder/src/live_builder/mod.rs | 14 +++++++++++--- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/crates/rbuilder/src/bin/dummy-builder.rs b/crates/rbuilder/src/bin/dummy-builder.rs index cb09bd0b..29c903b0 100644 --- a/crates/rbuilder/src/bin/dummy-builder.rs +++ b/crates/rbuilder/src/bin/dummy-builder.rs @@ -92,7 +92,7 @@ async fn main() -> eyre::Result<()> { Arc, MevBoostSlotDataGenerator, > { - watchdog_timeout: Duration::from_secs(10000), + watchdog_timeout: Some(Duration::from_secs(10000)), error_storage_path: None, simulation_threads: 1, blocks_source: payload_event, diff --git a/crates/rbuilder/src/live_builder/base_config.rs b/crates/rbuilder/src/live_builder/base_config.rs index a3aed895..83a58634 100644 --- a/crates/rbuilder/src/live_builder/base_config.rs +++ b/crates/rbuilder/src/live_builder/base_config.rs @@ -90,7 +90,7 @@ pub struct BaseConfig { /// compares result of root hash using sparse trie and reference root hash pub root_hash_compare_sparse_trie: bool, - pub watchdog_timeout_sec: u64, + pub watchdog_timeout_sec: Option, /// List of `builders` to be used for live building pub live_builders: Vec, @@ -321,8 +321,12 @@ impl BaseConfig { Ok(http_provider(self.backtest_fetch_eth_rpc_url.parse()?)) } - pub fn watchdog_timeout(&self) -> Duration { - Duration::from_secs(self.watchdog_timeout_sec) + pub fn watchdog_timeout(&self) -> Option { + match self.watchdog_timeout_sec { + Some(0) => None, + Some(sec) => Some(Duration::from_secs(sec)), + None => None, + } } pub fn backtest_fetch_mempool_data_dir(&self) -> eyre::Result { @@ -438,7 +442,7 @@ impl Default for BaseConfig { extra_data: "extra_data_change_me".to_string(), root_hash_use_sparse_trie: false, root_hash_compare_sparse_trie: false, - watchdog_timeout_sec: 60 * 3, + watchdog_timeout_sec: None, backtest_fetch_mempool_data_dir: "/mnt/data/mempool".into(), backtest_fetch_eth_rpc_url: "http://127.0.0.1:8545".to_string(), backtest_fetch_eth_rpc_parallel: 1, diff --git a/crates/rbuilder/src/live_builder/mod.rs b/crates/rbuilder/src/live_builder/mod.rs index 8e9b3f06..abdbd973 100644 --- a/crates/rbuilder/src/live_builder/mod.rs +++ b/crates/rbuilder/src/live_builder/mod.rs @@ -87,7 +87,7 @@ where P: StateProviderFactory + Clone, BlocksSourceType: SlotSource, { - pub watchdog_timeout: Duration, + pub watchdog_timeout: Option, pub error_storage_path: Option, pub simulation_threads: usize, pub order_input_config: OrderInputConfig, @@ -178,7 +178,13 @@ where self.run_sparse_trie_prefetcher, ); - let watchdog_sender = spawn_watchdog_thread(self.watchdog_timeout)?; + let watchdog_sender = match self.watchdog_timeout { + Some(duration) => Some(spawn_watchdog_thread(duration)?), + None => { + info!("Watchdog not enabled"); + None + } + }; while let Some(payload) = payload_events_channel.recv().await { if self.blocklist.contains(&payload.fee_recipient()) { @@ -247,7 +253,9 @@ where time_until_slot_end.try_into().unwrap_or_default(), ); - watchdog_sender.try_send(()).unwrap_or_default(); + if let Some(watchdog_sender) = watchdog_sender.as_ref() { + watchdog_sender.try_send(()).unwrap_or_default(); + }; } } From 93d5d5ee9a3efb5fbf8b1b187c37f78cf8e735d1 Mon Sep 17 00:00:00 2001 From: Benjamin Hunter Date: Thu, 5 Dec 2024 03:32:02 -0500 Subject: [PATCH 14/30] Fix typo (#265) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 📝 Summary Fixing a typo that triggered my OCD ## 💡 Motivation and Context --- ## ✅ I have completed the following steps: * [x] Run `make lint` * [x] Run `make test` * [ ] Added tests (if applicable) --- crates/rbuilder/src/live_builder/block_output/relay_submit.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/rbuilder/src/live_builder/block_output/relay_submit.rs b/crates/rbuilder/src/live_builder/block_output/relay_submit.rs index a1d96bcc..c0e3a571 100644 --- a/crates/rbuilder/src/live_builder/block_output/relay_submit.rs +++ b/crates/rbuilder/src/live_builder/block_output/relay_submit.rs @@ -198,7 +198,7 @@ async fn run_submit_to_relays_job( gas = block.sealed_block.gas_used, txs = block.sealed_block.body.transactions.len(), bundles, - buidler_name = block.builder_name, + builder_name = block.builder_name, fill_time_ms = block.trace.fill_time.as_millis(), finalize_time_ms = block.trace.finalize_time.as_millis(), ); From 024eb38c9e58eae5b57b54b915830b7062e09a05 Mon Sep 17 00:00:00 2001 From: Ferran Borreguero Date: Thu, 5 Dec 2024 10:37:28 +0000 Subject: [PATCH 15/30] Show error in config in reth-rbuilder (#266) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 📝 Summary Before, if there was an error in the config file, it would only show the context error "Config file parsing" but it would not show the specific error. This PR changes that and shows the full error. --- ## ✅ I have completed the following steps: * [x] Run `make lint` * [x] Run `make test` * [x] Added tests (if applicable) --- crates/reth-rbuilder/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/reth-rbuilder/src/main.rs b/crates/reth-rbuilder/src/main.rs index b44c1c15..1e0b2f20 100644 --- a/crates/reth-rbuilder/src/main.rs +++ b/crates/reth-rbuilder/src/main.rs @@ -156,7 +156,7 @@ where .await; if let Err(e) = result { - error!("Fatal rbuilder error: {}", e); + error!("Fatal rbuilder error: {:#}", e); process::exit(1); } From 39f4903805f61af8e73cfe84237f80e98e15e867 Mon Sep 17 00:00:00 2001 From: sukoneck <19413126+sukoneck@users.noreply.github.com> Date: Thu, 5 Dec 2024 08:45:40 -0700 Subject: [PATCH 16/30] label artifact version and feature selection in CI (#264) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 📝 Summary allow specifying compilation features and add version to artifact names in release workflow. --- ## ✅ I have completed the following steps: successful run: https://github.com/flashbots/rbuilder/actions/runs/12154595107 --- .github/workflows/release.yaml | 37 +++++++++++++++++----------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index ad985dee..2b8ceb62 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -6,21 +6,29 @@ on: - "v*" workflow_dispatch: inputs: + draft-release: + default: false + description: "Draft Release" + required: false + type: boolean build-docker: + default: false description: "Build Docker" required: false type: boolean - default: false build-binary: + default: true description: "Build Binary" required: false type: boolean - default: true - draft-release: - description: "Draft Release" + features: + default: '' + description: "Binary Compilation Features" + options: + - '' + - 'redact-sensitive' required: false - type: boolean - default: false + type: choice jobs: extract-version: @@ -35,14 +43,10 @@ jobs: if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then VERSION="${GITHUB_REF#refs/tags/}" else - SHA_SHORT="$(echo ${GITHUB_SHA} | cut -c1-7)" - BRANCH_NAME_SAFE="${GITHUB_REF_NAME//\//-}" # replaces "/" in branch name with "-" - VERSION="${BRANCH_NAME_SAFE}-${SHA_SHORT}" + VERSION="$(echo ${GITHUB_SHA} | cut -c1-7)" fi echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT - echo "${VERSION}" - echo "### Version: \`${VERSION}\`" >> $GITHUB_STEP_SUMMARY echo "| | |" >> $GITHUB_STEP_SUMMARY echo "| ------------------- | ---------------------- |" >> $GITHUB_STEP_SUMMARY echo "| \`GITHUB_REF_TYPE\` | \`${GITHUB_REF_TYPE}\` |" >> $GITHUB_STEP_SUMMARY @@ -50,6 +54,7 @@ jobs: echo "| \`GITHUB_REF\` | \`${GITHUB_REF}\` |" >> $GITHUB_STEP_SUMMARY echo "| \`GITHUB_SHA\` | \`${GITHUB_SHA}\` |" >> $GITHUB_STEP_SUMMARY echo "| \`VERSION\` | \`${VERSION}\` |" >> $GITHUB_STEP_SUMMARY + echo "| \`FEATURES\` | \`${{ github.event.inputs.features || 'none' }}\` |" >> $GITHUB_STEP_SUMMARY build-binary: name: Build binary @@ -58,8 +63,6 @@ jobs: runs-on: ${{ matrix.configs.runner }} container: image: ubuntu:22.04 - env: - VERSION: ${{ needs.extract-version.outputs.VERSION }} permissions: contents: write packages: write @@ -74,8 +77,7 @@ jobs: # - target: aarch64-apple-darwin # runner: warp-macos-14-arm64-6x features: - - "" - - "redact-sensitive" + - ${{ github.event.inputs.features || '' }} steps: - name: Install dependencies @@ -102,13 +104,13 @@ jobs: - name: Upload rbuilder artifact uses: actions/upload-artifact@v4 with: - name: rbuilder-${{ matrix.configs.target }}${{ matrix.features && '-' }}${{ matrix.features }} + name: rbuilder-${{ needs.extract-version.outputs.VERSION }}-${{ matrix.configs.target }}${{ matrix.features && '-' }}${{ matrix.features }} path: target/${{ matrix.configs.target }}/release/rbuilder - name: Upload reth-rbuilder artifact uses: actions/upload-artifact@v4 with: - name: reth-rbuilder-${{ matrix.configs.target }}${{ matrix.features && '-' }}${{ matrix.features }} + name: reth-rbuilder-${{ needs.extract-version.outputs.VERSION }}-${{ matrix.configs.target }}${{ matrix.features && '-' }}${{ matrix.features }} path: target/${{ matrix.configs.target }}/release/reth-rbuilder draft-release: @@ -174,7 +176,6 @@ jobs: - name: docker buildx uses: docker/setup-buildx-action@v3 - # https://github.com/docker/metadata-action - name: docker metadata uses: docker/metadata-action@v5 id: meta From f85e35c71647c51f18822bb7543584a39707b2c1 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Fri, 6 Dec 2024 15:54:47 +0100 Subject: [PATCH 17/30] chore: rm redundant arc (#268) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 📝 Summary remove arc wrapper around pool ## 💡 Motivation and Context Pool itself is already an Arc wrapper --- ## ✅ I have completed the following steps: * [ ] Run `make lint` * [ ] Run `make test` * [ ] Added tests (if applicable) --- .../src/bundle_supported_pool.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/crates/transaction-pool-bundle-ext/src/bundle_supported_pool.rs b/crates/transaction-pool-bundle-ext/src/bundle_supported_pool.rs index d956fc16..35d2cab0 100644 --- a/crates/transaction-pool-bundle-ext/src/bundle_supported_pool.rs +++ b/crates/transaction-pool-bundle-ext/src/bundle_supported_pool.rs @@ -55,7 +55,7 @@ use crate::{traits::BundlePoolOperations, TransactionPoolBundleExt}; #[derive(Debug)] pub struct BundleSupportedPool { /// Arc'ed instance of [`Pool`] internals - tx_pool: Arc>, + tx_pool: Pool, /// Arc'ed instance of the [`BundlePool`] internals bundle_pool: Arc>, } @@ -75,12 +75,7 @@ where tx_pool_config: PoolConfig, ) -> Self { Self { - tx_pool: Arc::new(Pool::::new( - validator, - ordering, - blob_store, - tx_pool_config, - )), + tx_pool: Pool::::new(validator, ordering, blob_store, tx_pool_config), bundle_pool: Arc::new(BundlePool::::new(bundle_ops)), } } @@ -102,7 +97,7 @@ impl BundlePool { impl Clone for BundleSupportedPool { fn clone(&self) -> Self { Self { - tx_pool: Arc::clone(&self.tx_pool), + tx_pool: self.tx_pool.clone(), bundle_pool: Arc::clone(&self.bundle_pool), } } From e13d221d6433b63e477a7513f1c41c71c0ff1459 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Fri, 6 Dec 2024 15:54:57 +0100 Subject: [PATCH 18/30] chore: replace std mutex with parking lot (#269) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 📝 Summary replaces std sync primitives with parking_lot's ## 💡 Motivation and Context parking_lot's primitives are more performant and don't come with lock poisoning, hence no unwrap https://docs.rs/parking_lot/latest/parking_lot/type.Mutex.html#differences-from-the-standard-library-mutex --- ## ✅ I have completed the following steps: * [ ] Run `make lint` * [ ] Run `make test` * [ ] Added tests (if applicable) --- .../bid_value_source/best_bid_sync_source.rs | 7 ++++--- .../bidding/parallel_sealer_bid_maker.rs | 13 +++++++------ .../bidding/sequential_sealer_bid_maker.rs | 12 +++++------- .../live_builder/block_output/relay_submit.rs | 7 ++++--- .../order_input/clean_orderpool.rs | 9 +++------ .../src/live_builder/order_input/mod.rs | 16 ++++++---------- .../src/live_builder/simulation/mod.rs | 9 +++++---- .../src/live_builder/simulation/sim_worker.rs | 5 +++-- crates/rbuilder/src/telemetry/dynamic_logs.rs | 15 ++++++--------- crates/rbuilder/src/utils/error_storage.rs | 11 ++++------- crates/rbuilder/src/utils/noncer.rs | 5 +++-- .../src/utils/provider_factory_reopen.rs | 19 ++++++------------- .../bundle_pool_ops/rbuilder/src/lib.rs | 2 +- 13 files changed, 57 insertions(+), 73 deletions(-) diff --git a/crates/rbuilder/src/live_builder/block_output/bid_value_source/best_bid_sync_source.rs b/crates/rbuilder/src/live_builder/block_output/bid_value_source/best_bid_sync_source.rs index c91ee984..387237c2 100644 --- a/crates/rbuilder/src/live_builder/block_output/bid_value_source/best_bid_sync_source.rs +++ b/crates/rbuilder/src/live_builder/block_output/bid_value_source/best_bid_sync_source.rs @@ -1,6 +1,7 @@ use super::interfaces::{BidValueObs, BidValueSource}; use alloy_primitives::U256; -use std::sync::{Arc, Mutex}; +use parking_lot::Mutex; +use std::sync::Arc; /// Simple struct tracking the last best bid and asking it in a sync way via best_bid_value. pub struct BestBidSyncSource { @@ -30,7 +31,7 @@ impl BestBidSyncSource { } pub fn best_bid_value(&self) -> Option { - *self.best_bid_source_inner.best_bid.lock().unwrap() + *self.best_bid_source_inner.best_bid.lock() } } @@ -41,7 +42,7 @@ struct BestBidSyncSourceInner { impl BidValueObs for BestBidSyncSourceInner { fn update_new_bid(&self, bid: U256) { - let mut best_bid = self.best_bid.lock().unwrap(); + let mut best_bid = self.best_bid.lock(); if best_bid.map_or(true, |old_bid| old_bid < bid) { *best_bid = Some(bid); } diff --git a/crates/rbuilder/src/live_builder/block_output/bidding/parallel_sealer_bid_maker.rs b/crates/rbuilder/src/live_builder/block_output/bidding/parallel_sealer_bid_maker.rs index b8e7ae9c..4f3d4eeb 100644 --- a/crates/rbuilder/src/live_builder/block_output/bidding/parallel_sealer_bid_maker.rs +++ b/crates/rbuilder/src/live_builder/block_output/bidding/parallel_sealer_bid_maker.rs @@ -1,4 +1,5 @@ -use std::sync::{Arc, Mutex}; +use parking_lot::Mutex; +use std::sync::Arc; use tokio::sync::Notify; use tokio_util::sync::CancellationToken; use tracing::error; @@ -38,13 +39,13 @@ impl PendingBid { } /// Updates bid, replacing on current (we assume they are always increasing but we don't check it). fn update(&self, bid: Bid) { - let mut current_bid = self.bid.lock().unwrap(); + let mut current_bid = self.bid.lock(); *current_bid = Some(bid); self.bid_notify.notify_one(); } fn consume_bid(&self) -> Option { - let mut current_bid = self.bid.lock().unwrap(); + let mut current_bid = self.bid.lock(); current_bid.take() } } @@ -113,7 +114,7 @@ impl ParallelSealerBidMakerProcess { /// block.finalize_block + self.sink.new_block inside spawn_blocking. async fn check_for_new_bid(&mut self) { - if *self.seal_control.seals_in_progress.lock().unwrap() >= self.max_concurrent_seals { + if *self.seal_control.seals_in_progress.lock() >= self.max_concurrent_seals { return; } if let Some(bid) = self.pending_bid.consume_bid() { @@ -121,7 +122,7 @@ impl ParallelSealerBidMakerProcess { let block = bid.block(); let block_number = block.building_context().block(); // Take sealing "slot" - *self.seal_control.seals_in_progress.lock().unwrap() += 1; + *self.seal_control.seals_in_progress.lock() += 1; let seal_control = self.seal_control.clone(); let sink = self.sink.clone(); tokio::task::spawn_blocking(move || { @@ -134,7 +135,7 @@ impl ParallelSealerBidMakerProcess { ), }; // release sealing "slot" - *seal_control.seals_in_progress.lock().unwrap() -= 1; + *seal_control.seals_in_progress.lock() -= 1; seal_control.notify.notify_one(); }); } diff --git a/crates/rbuilder/src/live_builder/block_output/bidding/sequential_sealer_bid_maker.rs b/crates/rbuilder/src/live_builder/block_output/bidding/sequential_sealer_bid_maker.rs index 3c729cb7..08f38cb6 100644 --- a/crates/rbuilder/src/live_builder/block_output/bidding/sequential_sealer_bid_maker.rs +++ b/crates/rbuilder/src/live_builder/block_output/bidding/sequential_sealer_bid_maker.rs @@ -1,10 +1,10 @@ -use std::sync::{Arc, Mutex}; +use crate::live_builder::block_output::relay_submit::BlockBuildingSink; +use parking_lot::Mutex; +use std::sync::Arc; use tokio::sync::Notify; use tokio_util::sync::CancellationToken; use tracing::error; -use crate::live_builder::block_output::relay_submit::BlockBuildingSink; - use super::interfaces::{Bid, BidMaker}; /// BidMaker with a background task sealing only one bid at a time. @@ -41,14 +41,12 @@ impl PendingBid { } /// Updates bid, replacing on current (we assume they are always increasing but we don't check it). fn update(&self, bid: Bid) { - let mut current_bid = self.bid.lock().unwrap(); - *current_bid = Some(bid); + *self.bid.lock() = Some(bid); self.bid_notify.notify_one(); } fn consume_bid(&self) -> Option { - let mut current_bid = self.bid.lock().unwrap(); - current_bid.take() + self.bid.lock().take() } } diff --git a/crates/rbuilder/src/live_builder/block_output/relay_submit.rs b/crates/rbuilder/src/live_builder/block_output/relay_submit.rs index c0e3a571..52053b1d 100644 --- a/crates/rbuilder/src/live_builder/block_output/relay_submit.rs +++ b/crates/rbuilder/src/live_builder/block_output/relay_submit.rs @@ -17,9 +17,10 @@ use crate::{ use ahash::HashMap; use alloy_primitives::{utils::format_ether, U256}; use mockall::automock; +use parking_lot::Mutex; use reth_chainspec::ChainSpec; use reth_primitives::SealedBlock; -use std::sync::{Arc, Mutex}; +use std::sync::Arc; use tokio::{sync::Notify, time::Instant}; use tokio_util::sync::CancellationToken; use tracing::{debug, error, event, info_span, trace, warn, Instrument, Level}; @@ -43,7 +44,7 @@ pub struct BestBlockCell { impl BestBlockCell { pub fn compare_and_update(&self, block: Block) { - let mut best_block = self.block.lock().unwrap(); + let mut best_block = self.block.lock(); let old_value = best_block .as_ref() .map(|b| b.trace.bid_value) @@ -55,7 +56,7 @@ impl BestBlockCell { } pub fn take_best_block(&self) -> Option { - self.block.lock().unwrap().take() + self.block.lock().take() } pub async fn wait_for_change(&self) { diff --git a/crates/rbuilder/src/live_builder/order_input/clean_orderpool.rs b/crates/rbuilder/src/live_builder/order_input/clean_orderpool.rs index 1a1e0e18..914f7fa6 100644 --- a/crates/rbuilder/src/live_builder/order_input/clean_orderpool.rs +++ b/crates/rbuilder/src/live_builder/order_input/clean_orderpool.rs @@ -5,12 +5,9 @@ use crate::{ }; use alloy_provider::{IpcConnect, Provider, ProviderBuilder}; use futures::StreamExt; +use parking_lot::Mutex; use reth_provider::StateProviderFactory; -use std::{ - pin::pin, - sync::{Arc, Mutex}, - time::Instant, -}; +use std::{pin::pin, sync::Arc, time::Instant}; use tokio::task::JoinHandle; use tokio_util::sync::CancellationToken; use tracing::{debug, error, info}; @@ -56,7 +53,7 @@ where } }; - let mut orderpool = orderpool.lock().unwrap(); + let mut orderpool = orderpool.lock(); let start = Instant::now(); orderpool.head_updated(block_number, &state); diff --git a/crates/rbuilder/src/live_builder/order_input/mod.rs b/crates/rbuilder/src/live_builder/order_input/mod.rs index d3ed5207..c807f31c 100644 --- a/crates/rbuilder/src/live_builder/order_input/mod.rs +++ b/crates/rbuilder/src/live_builder/order_input/mod.rs @@ -14,13 +14,9 @@ use self::{ }; use crate::primitives::{serialize::CancelShareBundle, BundleReplacementKey, Order}; use jsonrpsee::RpcModule; +use parking_lot::Mutex; use reth_provider::StateProviderFactory; -use std::{ - net::Ipv4Addr, - path::PathBuf, - sync::{Arc, Mutex}, - time::Duration, -}; +use std::{net::Ipv4Addr, path::PathBuf, sync::Arc, time::Duration}; use tokio::{sync::mpsc, task::JoinHandle}; use tokio_util::sync::CancellationToken; use tracing::{info, trace, warn}; @@ -39,14 +35,14 @@ impl OrderPoolSubscriber { block_number: u64, sink: Box, ) -> OrderPoolSubscriptionId { - self.orderpool.lock().unwrap().add_sink(block_number, sink) + self.orderpool.lock().add_sink(block_number, sink) } pub fn remove_sink( &self, id: &OrderPoolSubscriptionId, ) -> Option> { - self.orderpool.lock().unwrap().remove_sink(id) + self.orderpool.lock().remove_sink(id) } /// Returned AutoRemovingOrderPoolSubscriptionId will call remove when dropped @@ -72,7 +68,7 @@ pub struct AutoRemovingOrderPoolSubscriptionId { impl Drop for AutoRemovingOrderPoolSubscriptionId { fn drop(&mut self) { - self.orderpool.lock().unwrap().remove_sink(&self.id); + self.orderpool.lock().remove_sink(&self.id); } } @@ -272,7 +268,7 @@ where } { - let mut orderpool = orderpool.lock().unwrap(); + let mut orderpool = orderpool.lock(); orderpool.process_commands(new_commands.clone()); } new_commands.clear(); diff --git a/crates/rbuilder/src/live_builder/simulation/mod.rs b/crates/rbuilder/src/live_builder/simulation/mod.rs index 5e17a06d..8052d000 100644 --- a/crates/rbuilder/src/live_builder/simulation/mod.rs +++ b/crates/rbuilder/src/live_builder/simulation/mod.rs @@ -11,9 +11,10 @@ use crate::{ utils::gen_uid, }; use ahash::HashMap; +use parking_lot::Mutex; use reth_provider::StateProviderFactory; use simulation_job::SimulationJob; -use std::sync::{Arc, Mutex}; +use std::sync::Arc; use tokio::{sync::mpsc, task::JoinHandle}; use tokio_util::sync::CancellationToken; use tracing::{info_span, Instrument}; @@ -118,7 +119,7 @@ where let (sim_req_sender, sim_req_receiver) = flume::unbounded(); let (sim_results_sender, sim_results_receiver) = mpsc::channel(1024); { - let mut contexts = current_contexts.lock().unwrap(); + let mut contexts = current_contexts.lock(); let sim_context = SimulationContext { block_ctx: ctx, requests: sim_req_receiver, @@ -139,7 +140,7 @@ where // clean up { - let mut contexts = current_contexts.lock().unwrap(); + let mut contexts = current_contexts.lock(); contexts.contexts.remove(&block_context); } } @@ -147,7 +148,7 @@ where ); { - let mut tasks = self.running_tasks.lock().unwrap(); + let mut tasks = self.running_tasks.lock(); tasks.retain(|handle| !handle.is_finished()); tasks.push(handle); } diff --git a/crates/rbuilder/src/live_builder/simulation/sim_worker.rs b/crates/rbuilder/src/live_builder/simulation/sim_worker.rs index d37342b1..4c572dc2 100644 --- a/crates/rbuilder/src/live_builder/simulation/sim_worker.rs +++ b/crates/rbuilder/src/live_builder/simulation/sim_worker.rs @@ -7,10 +7,11 @@ use crate::{ telemetry, telemetry::add_sim_thread_utilisation_timings, }; +use parking_lot::Mutex; use reth::revm::cached::CachedReads; use reth_provider::StateProviderFactory; use std::{ - sync::{Arc, Mutex}, + sync::Arc, thread::sleep, time::{Duration, Instant}, }; @@ -34,7 +35,7 @@ pub fn run_sim_worker

( } let current_sim_context = loop { let next_ctx = { - let ctxs = ctx.lock().unwrap(); + let ctxs = ctx.lock(); ctxs.contexts.iter().next().map(|(_, c)| c.clone()) }; // @Perf chose random context so its more fair when we have 2 instead of 1 diff --git a/crates/rbuilder/src/telemetry/dynamic_logs.rs b/crates/rbuilder/src/telemetry/dynamic_logs.rs index 303a75c9..c88aed81 100644 --- a/crates/rbuilder/src/telemetry/dynamic_logs.rs +++ b/crates/rbuilder/src/telemetry/dynamic_logs.rs @@ -1,11 +1,8 @@ //! This module provides a functionality to dynamically change the log level use lazy_static::lazy_static; -use std::{ - fs::File, - path::PathBuf, - sync::{Arc, Mutex}, -}; +use parking_lot::Mutex; +use std::{fs::File, path::PathBuf, sync::Arc}; use tracing_subscriber::{ filter::Filtered, fmt, layer::SubscriberExt, reload, reload::Handle, util::SubscriberInitExt, EnvFilter, Layer, Registry, @@ -41,13 +38,13 @@ impl Default for LoggerConfig { } pub fn default_log_config() -> LoggerConfig { - DEFAULT_CONFIG.lock().unwrap().clone() + DEFAULT_CONFIG.lock().clone() } /// Reloads the log layer with the provided config pub fn set_log_config(config: LoggerConfig) -> eyre::Result<()> { let (env, write_layer) = create_filter_and_write_layer(&config)?; - let handle = RELOAD_HANDLE.lock().unwrap(); + let handle = RELOAD_HANDLE.lock(); handle .as_ref() .ok_or_else(|| eyre::eyre!("tracing subscriber is not set up"))? @@ -69,7 +66,7 @@ pub fn reset_log_config() -> eyre::Result<()> { /// To reload env filter, use `set_env_filter` and `reset_env_filter` functions pub fn setup_reloadable_tracing_subscriber(config: LoggerConfig) -> eyre::Result<()> { { - let mut default_config = DEFAULT_CONFIG.lock().unwrap(); + let mut default_config = DEFAULT_CONFIG.lock(); *default_config = config.clone(); } @@ -78,7 +75,7 @@ pub fn setup_reloadable_tracing_subscriber(config: LoggerConfig) -> eyre::Result let (reload_layer, reload_handle) = reload::Layer::new(layer); { - let mut handle = RELOAD_HANDLE.lock().unwrap(); + let mut handle = RELOAD_HANDLE.lock(); *handle = Some(reload_handle); } tracing_subscriber::registry().with(reload_layer).init(); diff --git a/crates/rbuilder/src/utils/error_storage.rs b/crates/rbuilder/src/utils/error_storage.rs index 25bf8d79..dab335cb 100644 --- a/crates/rbuilder/src/utils/error_storage.rs +++ b/crates/rbuilder/src/utils/error_storage.rs @@ -4,12 +4,9 @@ use crossbeam_queue::ArrayQueue; use lazy_static::lazy_static; +use parking_lot::Mutex; use sqlx::{sqlite::SqliteConnectOptions, ConnectOptions, Executor, SqliteConnection}; -use std::{ - path::Path, - sync::{Arc, Mutex}, - time::Duration, -}; +use std::{path::Path, sync::Arc, time::Duration}; use tokio_util::sync::CancellationToken; use tracing::{error, info_span, warn}; @@ -36,7 +33,7 @@ lazy_static! { } fn event_queue() -> Option>> { - EVENT_QUEUE.lock().unwrap().clone() + EVENT_QUEUE.lock().clone() } /// Spawn a new error storage writer. @@ -46,7 +43,7 @@ pub async fn spawn_error_storage_writer( global_cancel: CancellationToken, ) -> eyre::Result<()> { let mut storage = ErrorEventStorage::new_from_path(db_path).await?; - *EVENT_QUEUE.lock().unwrap() = Some(Arc::new(ArrayQueue::new(MAX_PENDING_EVENTS))); + *EVENT_QUEUE.lock() = Some(Arc::new(ArrayQueue::new(MAX_PENDING_EVENTS))); tokio::spawn(async move { while !global_cancel.is_cancelled() { if let Some(event_queue) = event_queue() { diff --git a/crates/rbuilder/src/utils/noncer.rs b/crates/rbuilder/src/utils/noncer.rs index 6e927e85..2fa7b218 100644 --- a/crates/rbuilder/src/utils/noncer.rs +++ b/crates/rbuilder/src/utils/noncer.rs @@ -1,9 +1,10 @@ use ahash::HashMap; use alloy_primitives::{Address, B256}; +use parking_lot::Mutex; use reth::providers::StateProviderBox; use reth_errors::ProviderResult; use reth_provider::StateProviderFactory; -use std::sync::{Arc, Mutex}; +use std::sync::Arc; /// Struct to get nonces for Addresses, caching the results. /// NonceCache contains the data (but doesn't allow you to query it) and NonceCacheRef is a reference that allows you to query it. @@ -48,7 +49,7 @@ pub struct NonceCacheRef { impl NonceCacheRef { pub fn nonce(&self, address: Address) -> ProviderResult { - let mut cache = self.cache.lock().unwrap(); + let mut cache = self.cache.lock(); if let Some(nonce) = cache.get(&address) { return Ok(*nonce); } diff --git a/crates/rbuilder/src/utils/provider_factory_reopen.rs b/crates/rbuilder/src/utils/provider_factory_reopen.rs index 1e4c674d..997e2382 100644 --- a/crates/rbuilder/src/utils/provider_factory_reopen.rs +++ b/crates/rbuilder/src/utils/provider_factory_reopen.rs @@ -1,6 +1,7 @@ use crate::telemetry::{inc_provider_bad_reopen_counter, inc_provider_reopen_counter}; use alloy_eips::{BlockNumHash, BlockNumberOrTag}; use alloy_primitives::{BlockHash, BlockNumber}; +use parking_lot::{Mutex, RwLock}; use reth::providers::{BlockHashReader, ChainSpecProvider, ProviderFactory}; use reth_chainspec::ChainInfo; use reth_db::{Database, DatabaseError}; @@ -13,11 +14,7 @@ use reth_provider::{ HeaderProvider, StateProviderBox, StateProviderFactory, StaticFileProviderFactory, }; use revm_primitives::{B256, U256}; -use std::{ - ops::RangeBounds, - path::PathBuf, - sync::{Arc, Mutex, RwLock}, -}; +use std::{ops::RangeBounds, path::PathBuf, sync::Arc}; use tracing::debug; /// This struct is used as a workaround for https://github.com/paradigmxyz/reth/issues/7836 @@ -71,7 +68,7 @@ impl ProviderFactoryReopener /// This will currently available provider factory without verifying if its correct, it can be used /// when consistency is not absolutely required pub fn provider_factory_unchecked(&self) -> ProviderFactory { - self.provider_factory.lock().unwrap().clone() + self.provider_factory.lock().clone() } /// This will check if historical block hashes for the given block is correct and if not it will reopen @@ -85,13 +82,10 @@ impl ProviderFactoryReopener .provider_factory_unchecked() .last_block_number() .map_err(|err| eyre::eyre!("Error getting best block number: {:?}", err))?; - let mut provider_factory = self.provider_factory.lock().unwrap(); + let mut provider_factory = self.provider_factory.lock(); // Don't need to check consistency for the block that was just checked. - let last_consistent_block_guard = self.last_consistent_block.read().unwrap(); - let last_consistent_block = *last_consistent_block_guard; - // Drop before write might be attempted to avoid deadlock! - drop(last_consistent_block_guard); + let last_consistent_block = *self.last_consistent_block.read(); if !self.testing_mode && last_consistent_block != Some(best_block_number) { match check_provider_factory_health(best_block_number, &provider_factory) { Ok(()) => {} @@ -120,8 +114,7 @@ impl ProviderFactoryReopener } } - let mut last_consistent_block = self.last_consistent_block.write().unwrap(); - *last_consistent_block = Some(best_block_number); + *self.last_consistent_block.write() = Some(best_block_number); } Ok(provider_factory.clone()) } diff --git a/crates/transaction-pool-bundle-ext/bundle_pool_ops/rbuilder/src/lib.rs b/crates/transaction-pool-bundle-ext/bundle_pool_ops/rbuilder/src/lib.rs index 0cdff24e..c66bc3a0 100644 --- a/crates/transaction-pool-bundle-ext/bundle_pool_ops/rbuilder/src/lib.rs +++ b/crates/transaction-pool-bundle-ext/bundle_pool_ops/rbuilder/src/lib.rs @@ -9,7 +9,6 @@ use std::{fmt::Formatter, path::Path, sync::Arc, time::Duration}; use alloy_primitives::U256; use alloy_rpc_types_beacon::events::PayloadAttributesEvent; use derive_more::From; -use rbuilder::live_builder::cli::LiveBuilderConfig; use rbuilder::{ building::{ builders::{ @@ -20,6 +19,7 @@ use rbuilder::{ }, live_builder::{ base_config::load_config_toml_and_env, + cli::LiveBuilderConfig, config::{create_builders, BuilderConfig, Config, SpecificBuilderConfig}, order_input::{rpc_server::RawCancelBundle, ReplaceableOrderPoolCommand}, payload_events::MevBoostSlotData, From 7239fa5082ec6a11b7b79272ac3d3b872bf0800f Mon Sep 17 00:00:00 2001 From: ZanCorDX <126988525+ZanCorDX@users.noreply.github.com> Date: Sat, 7 Dec 2024 20:31:12 -0300 Subject: [PATCH 19/30] remove_order wrongly routed (bug fix) (#270) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 📝 Summary BlockOrders remove orders was routed to MultiShareBundleMerger instead of PrioritizedOrderStore making failed orders cancellation fail. ## 💡 Motivation and Context Do I need a motivation to fix bugs? ## ✅ I have completed the following steps: * [X] Run `make lint` * [X] Run `make test` * [ ] Added tests (if applicable) --- crates/rbuilder/src/building/block_orders/mod.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/rbuilder/src/building/block_orders/mod.rs b/crates/rbuilder/src/building/block_orders/mod.rs index 5ea4c905..afc2e2b7 100644 --- a/crates/rbuilder/src/building/block_orders/mod.rs +++ b/crates/rbuilder/src/building/block_orders/mod.rs @@ -161,7 +161,9 @@ impl BlockOrders { &mut self, orders: impl IntoIterator, ) -> Vec { - self.input_order_store().remove_orders(orders) + self.prioritized_order_store + .borrow_mut() + .remove_orders(orders) } pub fn pop_order(&mut self) -> Option { From fac0b0319a01e3f712762b40d641e02690279b5e Mon Sep 17 00:00:00 2001 From: ZanCorDX <126988525+ZanCorDX@users.noreply.github.com> Date: Sun, 8 Dec 2024 11:01:09 -0300 Subject: [PATCH 20/30] Demoted traces (#271) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 📝 Summary Demoted some error! to info/warn. ## 💡 Motivation and Context These were giving fake emergency signals. ## ✅ I have completed the following steps: * [X] Run `make lint` * [X] Run `make test` * [ ] Added tests (if applicable) --- crates/rbuilder/src/building/builders/mod.rs | 4 ++-- .../block_output/bidding/wallet_balance_watcher.rs | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/crates/rbuilder/src/building/builders/mod.rs b/crates/rbuilder/src/building/builders/mod.rs index f25e5353..fd0d89bd 100644 --- a/crates/rbuilder/src/building/builders/mod.rs +++ b/crates/rbuilder/src/building/builders/mod.rs @@ -23,7 +23,7 @@ use reth_provider::{DatabaseProviderFactory, StateProviderFactory}; use std::{fmt::Debug, marker::PhantomData, sync::Arc}; use tokio::sync::{broadcast, broadcast::error::TryRecvError}; use tokio_util::sync::CancellationToken; -use tracing::{error, warn}; +use tracing::{info, warn}; /// Block we built #[derive(Debug, Clone)] @@ -249,7 +249,7 @@ pub fn handle_building_error(err: eyre::Report) -> bool { let err_str = err.to_string(); if !err_str.contains("Profit too low") { if is_provider_factory_health_error(&err) { - error!(?err, "Cancelling building due to provider factory error"); + info!(?err, "Cancelling building due to provider factory error"); return false; } else { warn!(?err, "Error filling orders"); diff --git a/crates/rbuilder/src/live_builder/block_output/bidding/wallet_balance_watcher.rs b/crates/rbuilder/src/live_builder/block_output/bidding/wallet_balance_watcher.rs index 7149315c..682c423a 100644 --- a/crates/rbuilder/src/live_builder/block_output/bidding/wallet_balance_watcher.rs +++ b/crates/rbuilder/src/live_builder/block_output/bidding/wallet_balance_watcher.rs @@ -4,7 +4,7 @@ use alloy_primitives::{utils::format_ether, Address, BlockNumber, U256}; use reth::providers::{HeaderProvider, ProviderError}; use reth_provider::StateProviderFactory; use time::{error, OffsetDateTime}; -use tracing::{error, info}; +use tracing::{error, info, warn}; use crate::telemetry::{add_subsidy_value, inc_subsidized_blocks}; @@ -144,7 +144,8 @@ where ) -> Result, WalletError> { if new_block <= self.block_number { if new_block < self.block_number { - error!( + // This happens due to reorgs and or weird slot/block generated by the CL + warn!( new_block, self.block_number, "Tried to update WalletBalanceWatcher to the past" ); From e11f170713188d1070b9f4d7e1febaab923c92e2 Mon Sep 17 00:00:00 2001 From: ZanCorDX <126988525+ZanCorDX@users.noreply.github.com> Date: Sun, 8 Dec 2024 11:07:11 -0300 Subject: [PATCH 21/30] Order intake consumer fix (#272) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 📝 Summary Ok(false) was not propagated. ## 💡 Motivation and Context It's a bug and I hate bugs (except for ladybugs and butterflies). ## ✅ I have completed the following steps: * [X] Run `make lint` * [X] Run `make test` * [ ] Added tests (if applicable) --- crates/rbuilder/src/building/builders/mod.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/rbuilder/src/building/builders/mod.rs b/crates/rbuilder/src/building/builders/mod.rs index fd0d89bd..c71f53e5 100644 --- a/crates/rbuilder/src/building/builders/mod.rs +++ b/crates/rbuilder/src/building/builders/mod.rs @@ -141,7 +141,9 @@ where /// Returns true if success, on false builder should stop pub fn consume_next_batch(&mut self) -> eyre::Result { - self.order_consumer.consume_next_commands()?; + if !self.order_consumer.consume_next_commands()? { + return Ok(false); + } self.update_onchain_nonces()?; self.order_consumer From 35b98fa6f781738cdd81fc28ac0b9d71966bf378 Mon Sep 17 00:00:00 2001 From: ZanCorDX <126988525+ZanCorDX@users.noreply.github.com> Date: Sun, 8 Dec 2024 11:11:04 -0300 Subject: [PATCH 22/30] OFAC non critical error fix (#273) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 📝 Summary This version considers the error from the relay "block rejected because of OFAC addresses" as non critical. ## 💡 Motivation and Context Without this change, non OFAC compliant builders would stop building blocks after sending a non-OFAC block to a OFAC complaint relay (flashbot's!). ## ✅ I have completed the following steps: * [X] Run `make lint` * [X] Run `make test` * [ ] Added tests (if applicable) --- crates/rbuilder/src/mev_boost/mod.rs | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/crates/rbuilder/src/mev_boost/mod.rs b/crates/rbuilder/src/mev_boost/mod.rs index 914d363e..f657776d 100644 --- a/crates/rbuilder/src/mev_boost/mod.rs +++ b/crates/rbuilder/src/mev_boost/mod.rs @@ -31,6 +31,16 @@ const GZIP_CONTENT_ENCODING: &str = "gzip"; const BUILDER_ID_HEADER: &str = "X-Builder-Id"; const API_TOKEN_HEADER: &str = "X-Api-Token"; +/// We don't have nice error codes for relay errors so we have to parse looking for substrings :( +/// Simulation error base. +const SIM_FAILED_SUBSTRING: &str = "simulation failed"; +/// Any error containing SIM_FAILED_SUBSTRING and any of SIM_FAILED_NON_CRITICAL_ERRORS is not critical so we should not stop block building. +const SIM_FAILED_NON_CRITICAL_ERRORS: &[&str] = &[ + "blacklisted address", // Generated block is good but contains a blacklisted address. This happens if we don't use an OFAC blacklist but the relay does. + "unknown ancestor", + "missing trie node", +]; + // @Org consolidate with primitives::mev_boost #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] @@ -268,7 +278,8 @@ pub enum SubmitBlockErr { PayloadDelivered, #[error("Bid below floor")] BidBelowFloor, - #[error("Simulation Error")] + #[cfg_attr(not(feature = "redact-sensitive"), error("Simulation Error: {0}"))] + #[cfg_attr(feature = "redact-sensitive", error("Simulation Error: [REDACTED]"))] SimError(String), #[error("RPC conversion Error")] /// RPC validates the submissions (eg: limit of txs) much more that our model. @@ -540,8 +551,11 @@ impl RelayClient { } "block already received" => Err(SubmitBlockErr::BlockKnown), _ if msg.contains("read tcp") => Err(RelayError::ConnectionError.into()), - _ if msg.contains("simulation failed") => { - if msg.contains("unknown ancestor") | msg.contains("missing trie node") { + _ if msg.contains(SIM_FAILED_SUBSTRING) => { + if SIM_FAILED_NON_CRITICAL_ERRORS + .iter() + .any(|pat| msg.contains(*pat)) + { Err(RelayError::InternalError.into()) } else { Err(SubmitBlockErr::SimError(msg.to_string())) From 17776ccfde349baed05b523883493c890918aac1 Mon Sep 17 00:00:00 2001 From: BraveBear <163831412+InventiveCoder@users.noreply.github.com> Date: Tue, 10 Dec 2024 17:35:54 +0800 Subject: [PATCH 23/30] chore: remove redundant words in comment (#275) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 📝 Summary remove redundant words in comment ## 💡 Motivation and Context --- ## ✅ I have completed the following steps: * [ ] Run `make lint` * [ ] Run `make test` * [ ] Added tests (if applicable) Signed-off-by: InventiveCoder --- .../rbuilder/src/building/block_orders/share_bundle_merger.rs | 2 +- .../block_output/bidding/sequential_sealer_bid_maker.rs | 2 +- crates/rbuilder/src/live_builder/simulation/mod.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/rbuilder/src/building/block_orders/share_bundle_merger.rs b/crates/rbuilder/src/building/block_orders/share_bundle_merger.rs index 20f59c71..41e7148a 100644 --- a/crates/rbuilder/src/building/block_orders/share_bundle_merger.rs +++ b/crates/rbuilder/src/building/block_orders/share_bundle_merger.rs @@ -216,7 +216,7 @@ impl MultiBackrunManager { /// - Backruns: It contains a sub bundle with the user txs followed by backrunner sub bundles. (see [`ShareBundleMerger::break_down_backrun_bundle`] for a clearer definition) /// Merging example: SBundle(Bundle(tx)+br1) + SBundle(Bundle(tx)+br2) will become SBundle(Bundle(Bundle(tx)+br1),Bundle(Bundle(tx)+br2)). /// User Bundle may contain more that one tx (for the case approve + swap). -/// This means what when we insert/remove orders (sbundles) we insert/remove the virtual bundles we generate and and not the original orders. +/// This means what when we insert/remove orders (sbundles) we insert/remove the virtual bundles we generate and not the original orders. /// We ONLY use this special flow for orders with some particular structure (see [`ShareBundleMerger::break_down_bundle`]). /// SBundle not complying with that will pass through and use the standard handling. /// @Pending evaluate if we can avoid to send changes no every order update and "flush" changes all together (since orders are usually processed on batches) diff --git a/crates/rbuilder/src/live_builder/block_output/bidding/sequential_sealer_bid_maker.rs b/crates/rbuilder/src/live_builder/block_output/bidding/sequential_sealer_bid_maker.rs index 08f38cb6..708a2be3 100644 --- a/crates/rbuilder/src/live_builder/block_output/bidding/sequential_sealer_bid_maker.rs +++ b/crates/rbuilder/src/live_builder/block_output/bidding/sequential_sealer_bid_maker.rs @@ -106,7 +106,7 @@ impl SequentialSealerBidMakerProcess { Err(error) => error!( block_number, ?error, - "Error on join finalize_block on on SequentialSealerBidMaker" + "Error on join finalize_block on SequentialSealerBidMaker" ), } } diff --git a/crates/rbuilder/src/live_builder/simulation/mod.rs b/crates/rbuilder/src/live_builder/simulation/mod.rs index 8052d000..963d62f7 100644 --- a/crates/rbuilder/src/live_builder/simulation/mod.rs +++ b/crates/rbuilder/src/live_builder/simulation/mod.rs @@ -95,7 +95,7 @@ where } /// Prepares the context to run a SimulationJob and spawns a task with it. - /// The returned SlotOrderSimResults can be polled to the the simulation stream. + /// The returned SlotOrderSimResults can be polled to the simulation stream. /// IMPORTANT: By calling spawn_simulation_job we lock some worker threads on the given block. /// When we are done we MUST call block_cancellation so the threads can be freed for the next block. /// @Pending: Not properly working to be used with several blocks at the same time (forks!). From 16290b62a7b1a7693b04589ce403013bee09b20b Mon Sep 17 00:00:00 2001 From: Ihor Farion <65650773+grasphoper@users.noreply.github.com> Date: Thu, 12 Dec 2024 13:20:09 -0800 Subject: [PATCH 24/30] Add more conflict types to `ConflictFinder` (#238) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 📝 Summary Add more conflict types to `ConflictFinder` as per [#226](https://github.com/flashbots/rbuilder/issues/226) ## A brief overview of the changes: - I added multiple new mapping entries to `ConflictFinder`, namely ```rust group_balance_reads: HashMap>, group_balance_writes: HashMap>, group_contract_creations: HashMap>, group_contract_destructions: HashMap>, ``` - Added conflicts that can be related to those fields - Added `combine_groups` - a utility fn to reuse code - Added `ConflictFinder.add_group_to_index` and `ConflictFinder.remove_group_from_index` to reuse code and improve readability; `index` here means search index, or different member mappings of `ConflictFinder` --- ## ✅ I have completed the following steps: * [x] Run `make lint` * [X] Run `make test` * [X] Added tests (if applicable) --------- Co-authored-by: dev --- .../builders/parallel_builder/groups.rs | 475 +++++++++++++----- 1 file changed, 359 insertions(+), 116 deletions(-) diff --git a/crates/rbuilder/src/building/builders/parallel_builder/groups.rs b/crates/rbuilder/src/building/builders/parallel_builder/groups.rs index 2e742341..ee024c47 100644 --- a/crates/rbuilder/src/building/builders/parallel_builder/groups.rs +++ b/crates/rbuilder/src/building/builders/parallel_builder/groups.rs @@ -5,6 +5,7 @@ use crate::{ use ahash::{HashMap, HashSet}; use alloy_primitives::U256; use itertools::Itertools; +use revm_primitives::{Address, B256}; use std::sync::Arc; @@ -31,15 +32,62 @@ struct GroupData { orders: Vec, reads: Vec, writes: Vec, + balance_reads: Vec

, + balance_writes: Vec
, + code_writes: Vec
, conflicting_group_ids: HashSet, } +// if we're removing a group id from ConflictFinder.groups and adding its contents under some other group, +// we pass its id inside `removed_group_ids` +fn combine_groups(groups: Vec, removed_group_ids: Vec) -> GroupData { + let mut orders = Vec::default(); + let mut reads = Vec::default(); + let mut writes = Vec::default(); + let mut balance_reads = Vec::default(); + let mut balance_writes = Vec::default(); + let mut code_writes = Vec::default(); + let mut conflicting_group_ids = removed_group_ids.into_iter().collect::>(); + for group in groups { + orders.extend(group.orders); + reads.extend(group.reads); + writes.extend(group.writes); + balance_reads.extend(group.balance_reads); + balance_writes.extend(group.balance_writes); + code_writes.extend(group.code_writes); + conflicting_group_ids.extend(group.conflicting_group_ids); + } + reads.sort_unstable(); + reads.dedup(); + writes.sort_unstable(); + writes.dedup(); + balance_reads.sort_unstable(); + balance_reads.dedup(); + balance_writes.sort_unstable(); + balance_writes.dedup(); + code_writes.sort_unstable(); + code_writes.dedup(); + + GroupData { + orders, + reads, + writes, + balance_reads, + balance_writes, + code_writes, + conflicting_group_ids, + } +} + /// ConflictFinder is used to quickly find and update groups of orders that conflict with each other. #[derive(Debug)] pub struct ConflictFinder { group_counter: usize, - group_reads: HashMap>, - group_writes: HashMap>, + group_reads: HashMap>>, // mapping by `SlotKey`, but SlotKey.address and SlotKey.key are split into 2 separate HashMap keys + group_writes: HashMap>>, // same as above + group_balance_reads: HashMap>, + group_balance_writes: HashMap>, + group_code_writes: HashMap>, groups: HashMap, orders: HashSet, } @@ -50,6 +98,9 @@ impl ConflictFinder { group_counter: 0, group_reads: HashMap::default(), group_writes: HashMap::default(), + group_balance_reads: HashMap::default(), + group_balance_writes: HashMap::default(), + group_code_writes: HashMap::default(), groups: HashMap::default(), orders: HashSet::default(), } @@ -70,149 +121,199 @@ impl ConflictFinder { let mut all_groups_in_conflict = Vec::new(); + // check for all possible conflict types for read_key in used_state.read_slot_values.keys() { - if let Some(group) = self.group_writes.get(read_key) { + // reading from slot to which other order is writing to + if let Some(inner_mapping) = self.group_writes.get(&read_key.address) { + if let Some(groups) = inner_mapping.get(&read_key.key) { + all_groups_in_conflict.extend_from_slice(groups); + } + } + // reading from slot on contract that other order is creating / destroying + if let Some(group) = self.group_code_writes.get(&read_key.address) { all_groups_in_conflict.extend_from_slice(group); } } for write_key in used_state.written_slot_values.keys() { - if let Some(group) = self.group_reads.get(write_key) { + // writing to slot other order is reading from + if let Some(inner_mapping) = self.group_reads.get(&write_key.address) { + if let Some(groups) = inner_mapping.get(&write_key.key) { + all_groups_in_conflict.extend_from_slice(groups); + } + } + // writing to slot on contract that other order is creating / destroying + if let Some(group) = self.group_code_writes.get(&write_key.address) { + all_groups_in_conflict.extend_from_slice(group); + } + } + // writing balance other order is reading + for write_balance_key in used_state + .received_amount + .keys() + .chain(used_state.sent_amount.keys()) + { + if let Some(group) = self.group_balance_reads.get(write_balance_key) { + all_groups_in_conflict.extend_from_slice(group); + } + } + // reading balance other order is writing + for read_balance_key in used_state.read_balances.keys() { + if let Some(group) = self.group_balance_writes.get(read_balance_key) { all_groups_in_conflict.extend_from_slice(group); } } + for contract_addr in used_state + .destructed_contracts + .iter() + .chain(used_state.created_contracts.iter()) + { + // trying to create / destroy a contract on the same addr as other order + if let Some(group) = self.group_code_writes.get(contract_addr) { + all_groups_in_conflict.extend_from_slice(group); + } + // trying to create / destroy a contract other order is trying to read from + if let Some(inner_mapping) = self.group_reads.get(contract_addr) { + let inner_groups = inner_mapping.values().flatten(); + all_groups_in_conflict.extend(inner_groups); + } + // trying to create / destroy a contract other order is trying to write to + if let Some(inner_mapping) = self.group_writes.get(contract_addr) { + let inner_groups = inner_mapping.values().flatten(); + all_groups_in_conflict.extend(inner_groups); + } + } all_groups_in_conflict.sort(); all_groups_in_conflict.dedup(); + // create new group with only the new order in it + let new_order_group: GroupData = { + let mut balance_writes: Vec
= used_state + .sent_amount + .into_keys() + .chain(used_state.received_amount.into_keys()) + .collect(); + balance_writes.sort_unstable(); + balance_writes.dedup(); + + let mut code_writes: Vec
= used_state + .created_contracts + .into_iter() + .chain(used_state.destructed_contracts.into_iter()) + .collect(); + code_writes.sort_unstable(); + code_writes.dedup(); + + GroupData { + orders: vec![order], + reads: used_state.read_slot_values.into_keys().collect(), + writes: used_state.written_slot_values.into_keys().collect(), + balance_reads: used_state.read_balances.into_keys().collect(), + balance_writes, + code_writes, + conflicting_group_ids: HashSet::default(), + } + }; + match all_groups_in_conflict.len() { 0 => { - // create new group with only one order in it + // add `new_order_group` to index and `groups` under a new `group_id` let group_id = self.group_counter; self.group_counter += 1; - let group_data = GroupData { - orders: vec![order], - reads: used_state.read_slot_values.keys().cloned().collect(), - writes: used_state.written_slot_values.keys().cloned().collect(), - conflicting_group_ids: HashSet::default(), - }; - for read in &group_data.reads { - self.group_reads - .entry(read.clone()) - .or_default() - .push(group_id); - } - for write in &group_data.writes { - self.group_writes - .entry(write.clone()) - .or_default() - .push(group_id); - } - self.groups.insert(group_id, group_data); + self.add_group_to_index(group_id, true, &new_order_group); + self.groups.insert(group_id, new_order_group); } 1 => { - // merge order into the group + // combine `new_order_group` with the conflicting group under the conflicting group's `group_id` let group_id = all_groups_in_conflict[0]; - let group_data = self.groups.get_mut(&group_id).expect("group not found"); - group_data.orders.push(order); - for read in used_state.read_slot_values.keys() { - group_data.reads.push(read.clone()); - } - group_data.reads.sort(); - group_data.reads.dedup(); - for write in used_state.written_slot_values.keys() { - group_data.writes.push(write.clone()); - } - group_data.writes.sort(); - group_data.writes.dedup(); - for read in &group_data.reads { - let group_reads_slot = self.group_reads.entry(read.clone()).or_default(); - if !group_reads_slot.contains(&group_id) { - group_reads_slot.push(group_id); - } - } - for write in &group_data.writes { - let group_writes_slot = self.group_writes.entry(write.clone()).or_default(); - if !group_writes_slot.contains(&group_id) { - group_writes_slot.push(group_id); - } - } + let other_group = self.groups.remove(&group_id).expect("group not found"); + let combined_group = combine_groups(vec![new_order_group, other_group], vec![]); + self.add_group_to_index(group_id, false, &combined_group); + self.groups.insert(group_id, combined_group); } _ => { - // merge multiple group together and add new order there + // combine `new_order_group` with multiple conflicting groups under a new `group_id` let conflicting_groups = all_groups_in_conflict .into_iter() .map(|group_id| (group_id, self.groups.remove(&group_id).unwrap())) .collect::>(); - // Collect all conflicting group IDs - let merged_conflicting_ids = conflicting_groups - .iter() - .flat_map(|(gid, gd)| { - gd.conflicting_group_ids - .iter() - .cloned() - .chain(std::iter::once(*gid)) - }) - .collect::>(); - for (group_id, group_data) in &conflicting_groups { - for read in &group_data.reads { - let group_reads_slot = - self.group_reads.entry(read.clone()).or_default(); - if let Some(idx) = group_reads_slot.iter().position(|el| el == group_id) - { - group_reads_slot.swap_remove(idx); - } - } - for write in &group_data.writes { - let group_writes_slot = - self.group_writes.entry(write.clone()).or_default(); - if let Some(idx) = - group_writes_slot.iter().position(|el| el == group_id) - { - group_writes_slot.swap_remove(idx); - } - } + self.remove_group_from_index(*group_id, group_data); } let group_id = self.group_counter; self.group_counter += 1; - let mut group_data = GroupData { - orders: vec![order], - reads: used_state.read_slot_values.keys().cloned().collect(), - writes: used_state.written_slot_values.keys().cloned().collect(), - conflicting_group_ids: merged_conflicting_ids, - }; - for (_, mut group) in conflicting_groups { - group_data.orders.append(&mut group.orders); - group_data.reads.append(&mut group.reads); - group_data.writes.append(&mut group.writes); - group_data - .conflicting_group_ids - .extend(group.conflicting_group_ids); - } - group_data.reads.sort(); - group_data.reads.dedup(); - group_data.writes.sort(); - group_data.writes.dedup(); - for read in &group_data.reads { - self.group_reads - .entry(read.clone()) - .or_default() - .push(group_id); - } - for write in &group_data.writes { - self.group_writes - .entry(write.clone()) - .or_default() - .push(group_id); - } - self.groups.insert(group_id, group_data); + let removed_group_ids = conflicting_groups.iter().map(|(id, _)| *id).collect(); + let conflicting_groups = conflicting_groups + .into_iter() + .map(|(_, group)| group) + .chain(std::iter::once(new_order_group)) + .collect(); + let combined_group = combine_groups(conflicting_groups, removed_group_ids); + + self.add_group_to_index(group_id, true, &combined_group); + self.groups.insert(group_id, combined_group); } } } } + fn add_group_to_index(&mut self, group_id: usize, is_new_id: bool, group_data: &GroupData) { + for read in &group_data.reads { + let address_reads = self.group_reads.entry(read.address).or_default(); + add_group_key_to_map(group_id, is_new_id, &read.key, address_reads); + } + for write in &group_data.writes { + let address_writes = self.group_writes.entry(write.address).or_default(); + add_group_key_to_map(group_id, is_new_id, &write.key, address_writes); + } + add_group_to_map( + group_id, + is_new_id, + &group_data.balance_reads, + &mut self.group_balance_reads, + ); + add_group_to_map( + group_id, + is_new_id, + &group_data.balance_writes, + &mut self.group_balance_writes, + ); + add_group_to_map( + group_id, + is_new_id, + &group_data.code_writes, + &mut self.group_code_writes, + ); + } + + fn remove_group_from_index(&mut self, group_id: usize, group_data: &GroupData) { + for read in &group_data.reads { + let address_reads = self.group_reads.entry(read.address).or_default(); + remove_group_key_from_map(group_id, &read.key, address_reads); + } + for write in &group_data.writes { + let address_writes = self.group_writes.entry(write.address).or_default(); + remove_group_key_from_map(group_id, &write.key, address_writes); + } + remove_group_from_map( + group_id, + &group_data.balance_reads, + &mut self.group_balance_reads, + ); + remove_group_from_map( + group_id, + &group_data.balance_writes, + &mut self.group_balance_writes, + ); + remove_group_from_map( + group_id, + &group_data.code_writes, + &mut self.group_code_writes, + ); + } + pub fn get_order_groups(&self) -> Vec { self.groups .iter() @@ -232,6 +333,51 @@ impl Default for ConflictFinder { } } +fn add_group_to_map( + group_id: usize, + is_new_id: bool, + group_keys: &Vec, + map: &mut HashMap>, +) { + for key in group_keys { + add_group_key_to_map(group_id, is_new_id, key, map); + } +} + +// if the `group_id` is new, we don't check if the map already contains it +fn add_group_key_to_map( + group_id: usize, + is_new_id: bool, + key: &K, + map: &mut HashMap>, +) { + let groups = map.entry(key.clone()).or_default(); + if is_new_id || !groups.contains(&group_id) { + groups.push(group_id); + } +} + +fn remove_group_from_map( + group_id: usize, + group_keys: &Vec, + map: &mut HashMap>, +) { + for key in group_keys { + remove_group_key_from_map(group_id, key, map); + } +} + +fn remove_group_key_from_map( + group_id: usize, + key: &K, + map: &mut HashMap>, +) { + let groups = map.entry(key.clone()).or_default(); + if let Some(idx) = groups.iter().position(|el| *el == group_id) { + groups.swap_remove(idx); + } +} + #[cfg(test)] mod tests { use alloy_consensus::TxLegacy; @@ -294,6 +440,10 @@ mod tests { &mut self, read: Option<&SlotKey>, write: Option<&SlotKey>, + balance_read: Option<&Address>, + balance_write: Option<&Address>, + contract_creation: Option<&Address>, + contract_destruction: Option<&Address>, ) -> SimulatedOrder { let mut trace = UsedStateTrace::default(); if let Some(read) = read { @@ -306,6 +456,23 @@ mod tests { .written_slot_values .insert(write.clone(), self.create_b256()); } + if let Some(balance_read) = balance_read { + trace + .read_balances + .insert(*balance_read, self.create_u256()); + } + if let Some(balance_write) = balance_write { + trace + .received_amount + .insert(*balance_write, self.create_u256()); + trace.sent_amount.insert(*balance_write, self.create_u256()); + } + if let Some(contract_address) = contract_creation { + trace.created_contracts.push(*contract_address); + } + if let Some(contract_address) = contract_destruction { + trace.destructed_contracts.push(*contract_address); + } SimulatedOrder { order: Order::Tx(MempoolTx { @@ -325,9 +492,9 @@ mod tests { fn two_writes_single_read() { let mut data_gen = DataGenerator::new(); let slot = data_gen.create_slot(); - let oa = data_gen.create_order(None, Some(&slot)); - let ob = data_gen.create_order(None, Some(&slot)); - let oc = data_gen.create_order(Some(&slot), None); + let oa = data_gen.create_order(None, Some(&slot), None, None, None, None); + let ob = data_gen.create_order(None, Some(&slot), None, None, None, None); + let oc = data_gen.create_order(Some(&slot), None, None, None, None, None); let mut cached_groups = ConflictFinder::new(); cached_groups.add_orders(vec![oa, ob, oc]); let groups = cached_groups.get_order_groups(); @@ -338,8 +505,8 @@ mod tests { fn two_reads() { let mut data_gen = DataGenerator::new(); let slot = data_gen.create_slot(); - let oa = data_gen.create_order(Some(&slot), None); - let ob = data_gen.create_order(Some(&slot), None); + let oa = data_gen.create_order(Some(&slot), None, None, None, None, None); + let ob = data_gen.create_order(Some(&slot), None, None, None, None, None); let mut cached_groups = ConflictFinder::new(); cached_groups.add_orders(vec![oa, ob]); let groups = cached_groups.get_order_groups(); @@ -350,11 +517,87 @@ mod tests { fn two_writes() { let mut data_gen = DataGenerator::new(); let slot = data_gen.create_slot(); - let oa = data_gen.create_order(None, Some(&slot)); - let ob = data_gen.create_order(None, Some(&slot)); + let oa = data_gen.create_order(None, Some(&slot), None, None, None, None); + let ob = data_gen.create_order(None, Some(&slot), None, None, None, None); + let mut cached_groups = ConflictFinder::new(); + cached_groups.add_orders(vec![oa, ob]); + let groups = cached_groups.get_order_groups(); + assert_eq!(groups.len(), 2); + } + + #[test] + fn two_balance_writes() { + let mut data_gen = DataGenerator::new(); + let address = data_gen.create_slot().address; + let oa = data_gen.create_order(None, None, None, Some(&address), None, None); + let ob = data_gen.create_order(None, None, None, Some(&address), None, None); let mut cached_groups = ConflictFinder::new(); cached_groups.add_orders(vec![oa, ob]); let groups = cached_groups.get_order_groups(); assert_eq!(groups.len(), 2); } + + #[test] + fn two_balance_reads() { + let mut data_gen = DataGenerator::new(); + let address = data_gen.create_slot().address; + let oa = data_gen.create_order(None, None, Some(&address), None, None, None); + let ob = data_gen.create_order(None, None, Some(&address), None, None, None); + let mut cached_groups = ConflictFinder::new(); + cached_groups.add_orders(vec![oa, ob]); + let groups = cached_groups.get_order_groups(); + assert_eq!(groups.len(), 2); + } + + #[test] + fn two_balance_writes_single_read() { + let mut data_gen = DataGenerator::new(); + let address = data_gen.create_slot().address; + let oa = data_gen.create_order(None, None, None, Some(&address), None, None); + let ob = data_gen.create_order(None, None, None, Some(&address), None, None); + let oc = data_gen.create_order(None, None, Some(&address), None, None, None); + let mut cached_groups = ConflictFinder::new(); + cached_groups.add_orders(vec![oa, ob, oc]); + let groups = cached_groups.get_order_groups(); + assert_eq!(groups.len(), 1); + } + + #[test] + fn two_contract_destructions() { + let mut data_gen = DataGenerator::new(); + let address = data_gen.create_slot().address; + let oa = data_gen.create_order(None, None, None, None, None, Some(&address)); + let ob = data_gen.create_order(None, None, None, None, None, Some(&address)); + let mut cached_groups = ConflictFinder::new(); + cached_groups.add_orders(vec![oa, ob]); + let groups = cached_groups.get_order_groups(); + assert_eq!(groups.len(), 1); + } + + #[test] + fn write_and_contract_destruction() { + let mut data_gen = DataGenerator::new(); + let write_slot = data_gen.create_slot(); + let destruction_addr = write_slot.address; + let oa = data_gen.create_order(None, Some(&write_slot), None, None, None, None); + let ob = data_gen.create_order(None, None, None, None, None, Some(&destruction_addr)); + let mut cached_groups = ConflictFinder::new(); + cached_groups.add_orders(vec![oa, ob]); + let groups = cached_groups.get_order_groups(); + assert_eq!(groups.len(), 1); + } + + #[test] + fn two_reads_one_destruction() { + let mut data_gen = DataGenerator::new(); + let read_slot = data_gen.create_slot(); + let destruction_addr = read_slot.address; + let oa = data_gen.create_order(Some(&read_slot), None, None, None, None, None); + let ob = data_gen.create_order(Some(&read_slot), None, None, None, None, None); + let oc = data_gen.create_order(None, None, None, None, None, Some(&destruction_addr)); + let mut cached_groups = ConflictFinder::new(); + cached_groups.add_orders(vec![oa, ob, oc]); + let groups = cached_groups.get_order_groups(); + assert_eq!(groups.len(), 1); + } } From 5ba3eff9611589f84eb97f06fba47091baab790b Mon Sep 17 00:00:00 2001 From: ZanCorDX <126988525+ZanCorDX@users.noreply.github.com> Date: Fri, 13 Dec 2024 11:28:17 -0300 Subject: [PATCH 25/30] OrderIntakeConsumer fixes for less warninig. (#281) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 📝 Summary - Stop building on reorg - update_onchain_nonces result propagated ## 💡 Motivation and Context Warninig annoy me --- ## ✅ I have completed the following steps: * [x] Run `make lint` * [x] Run `make test` * [ ] Added tests (if applicable) --- crates/rbuilder/src/building/builders/mod.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/crates/rbuilder/src/building/builders/mod.rs b/crates/rbuilder/src/building/builders/mod.rs index c71f53e5..2297a4c2 100644 --- a/crates/rbuilder/src/building/builders/mod.rs +++ b/crates/rbuilder/src/building/builders/mod.rs @@ -19,6 +19,7 @@ use reth::{ revm::cached::CachedReads, }; use reth_db::Database; +use reth_errors::ProviderError; use reth_provider::{DatabaseProviderFactory, StateProviderFactory}; use std::{fmt::Debug, marker::PhantomData, sync::Arc}; use tokio::sync::{broadcast, broadcast::error::TryRecvError}; @@ -144,7 +145,9 @@ where if !self.order_consumer.consume_next_commands()? { return Ok(false); } - self.update_onchain_nonces()?; + if !self.update_onchain_nonces()? { + return Ok(false); + } self.order_consumer .apply_new_commands(&mut self.block_orders); @@ -161,7 +164,11 @@ where SimulatedOrderCommand::Simulation(sim_order) => Some(sim_order), SimulatedOrderCommand::Cancellation(_) => None, }); - let nonce_db_ref = self.nonce_cache.get_ref()?; + let nonce_db_ref = match self.nonce_cache.get_ref() { + Ok(nonce_db_ref) => nonce_db_ref, + Err(ProviderError::BlockHashNotFound(_)) => return Ok(false), // This can happen on reorgs since the block is removed + Err(err) => return Err(err.into()), + }; let mut nonces = Vec::new(); for new_order in new_orders { for nonce in new_order.order.nonces() { From b60507660e4e07dded7394baebf4fe1f4abe13e1 Mon Sep 17 00:00:00 2001 From: ZanCorDX <126988525+ZanCorDX@users.noreply.github.com> Date: Fri, 13 Dec 2024 11:30:47 -0300 Subject: [PATCH 26/30] Parallel builder polish (#282) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 📝 Summary Less warning/errors and error handling improved a little. ## ✅ I have completed the following steps: * [X] Run `make lint` * [X] Run `make test` * [ ] Added tests (if applicable) --- .../block_building_result_assembler.rs | 34 +++++++++++-------- .../conflict_resolving_pool.rs | 11 ++++-- .../conflict_task_generator.rs | 23 +++++++------ 3 files changed, 41 insertions(+), 27 deletions(-) diff --git a/crates/rbuilder/src/building/builders/parallel_builder/block_building_result_assembler.rs b/crates/rbuilder/src/building/builders/parallel_builder/block_building_result_assembler.rs index 37b95347..7e1c02bc 100644 --- a/crates/rbuilder/src/building/builders/parallel_builder/block_building_result_assembler.rs +++ b/crates/rbuilder/src/building/builders/parallel_builder/block_building_result_assembler.rs @@ -10,13 +10,13 @@ use reth_provider::{BlockReader, DatabaseProviderFactory, StateProviderFactory}; use std::{marker::PhantomData, sync::Arc, time::Instant}; use time::OffsetDateTime; use tokio_util::sync::CancellationToken; -use tracing::{trace, warn}; +use tracing::{info_span, trace}; use crate::{ building::{ builders::{ block_building_helper::{BlockBuildingHelper, BlockBuildingHelperFromProvider}, - UnfinishedBlockBuildingSink, + handle_building_error, UnfinishedBlockBuildingSink, }, BlockBuildingContext, }, @@ -104,7 +104,9 @@ where } if self.best_results.get_number_of_orders() > 0 { let orders_closed_at = OffsetDateTime::now_utc(); - self.try_build_block(orders_closed_at); + if !self.try_build_block(orders_closed_at) { + break; + } } } trace!( @@ -113,12 +115,12 @@ where ); } - /// Attempts to build a new block if not already building. + /// Attempts to build a new block if not already building. Returns if block building should continue. /// /// # Arguments /// /// * `orders_closed_at` - The timestamp when orders were closed. - fn try_build_block(&mut self, orders_closed_at: OffsetDateTime) { + fn try_build_block(&mut self, orders_closed_at: OffsetDateTime) -> bool { let time_start = Instant::now(); let current_best_results = self.best_results.clone(); @@ -128,7 +130,7 @@ where // Check if version has incremented if let Some(last_version) = self.last_version { if version == last_version { - return; + return true; } } self.last_version = Some(version); @@ -140,18 +142,18 @@ where ); if best_orderings_per_group.is_empty() { - return; + return true; } match self.build_new_block(&mut best_orderings_per_group, orders_closed_at) { Ok(new_block) => { if let Ok(value) = new_block.true_block_value() { trace!( - "Parallel builder run id {}: Built new block with results version {:?} and profit: {:?} in {:?} ms", - self.run_id, - version, - format_ether(value), - time_start.elapsed().as_millis() + run_id = self.run_id, + version = version, + time_ms = time_start.elapsed().as_millis(), + profit = format_ether(value), + "Parallel builder built new block", ); if new_block.built_block_trace().got_no_signer_error { @@ -163,11 +165,15 @@ where } } } - Err(e) => { - warn!("Parallel builder run id {}: Failed to build new block with results version {:?}: {:?}", self.run_id, version, e); + Err(err) => { + let _span = info_span!("Parallel builder failed to build new block",run_id = self.run_id,version = version,err=?err).entered(); + if !handle_building_error(err) { + return false; + } } } self.run_id += 1; + true } /// Builds a new block using the best results from each group. diff --git a/crates/rbuilder/src/building/builders/parallel_builder/conflict_resolving_pool.rs b/crates/rbuilder/src/building/builders/parallel_builder/conflict_resolving_pool.rs index a6ac2b72..e9571eff 100644 --- a/crates/rbuilder/src/building/builders/parallel_builder/conflict_resolving_pool.rs +++ b/crates/rbuilder/src/building/builders/parallel_builder/conflict_resolving_pool.rs @@ -69,6 +69,9 @@ where self.thread_pool.spawn(move || { while !cancellation_token.is_cancelled() { if let Some(task) = task_queue.pop() { + if cancellation_token.is_cancelled() { + return; + } let task_start = Instant::now(); if let Ok((task_id, result)) = Self::process_task( task, @@ -92,6 +95,7 @@ where time_taken_ms = %task_start.elapsed().as_millis(), "Conflict resolving: failed to send group result" ); + return; } } } @@ -100,7 +104,7 @@ where }); } - pub fn process_task( + fn process_task( task: ConflictTask, ctx: &BlockBuildingContext, provider: &P, @@ -131,8 +135,9 @@ where } Err(err) => { warn!( - "Error running conflict task for group_idx {}: {:?}", - task_id, err + group_id = task_id, + err = ?err, + "Error running conflict task for group_idx", ); Err(err) } diff --git a/crates/rbuilder/src/building/builders/parallel_builder/conflict_task_generator.rs b/crates/rbuilder/src/building/builders/parallel_builder/conflict_task_generator.rs index 9750dc80..55b2f6dd 100644 --- a/crates/rbuilder/src/building/builders/parallel_builder/conflict_task_generator.rs +++ b/crates/rbuilder/src/building/builders/parallel_builder/conflict_task_generator.rs @@ -106,7 +106,7 @@ impl ConflictTaskGenerator { .cloned() .collect(); - trace!("Removing subset groups: {:?}", subset_ids); + trace!(groups = ?subset_ids,"Removing subset groups"); for id in subset_ids { self.existing_groups.remove(&id); self.cancel_tasks_for_group(id); @@ -158,10 +158,12 @@ impl ConflictTaskGenerator { TaskPriority::High }; trace!( - "Processing multi order group {group_id} with {} orders, {} profit with priority {:?}", - new_group.orders.len(), - format_ether(self.sum_top_n_profits(&new_group.orders, new_group.orders.len())), - priority.display() + group = group_id, + order_count = new_group.orders.len(), + profit = + format_ether(self.sum_top_n_profits(&new_group.orders, new_group.orders.len())), + priority = priority.display(), + "Processing multi order group" ); if self.existing_groups.contains_key(&group_id) { self.update_tasks(group_id, new_group, priority); @@ -186,8 +188,9 @@ impl ConflictTaskGenerator { .send((group_id, (sequence_of_orders, group.clone()))) { warn!( - "Failed to send single order result for group {}: {:?}", - group_id, e + error = ?e, + group_id, + "Failed to send single order result for group", ); } } @@ -294,9 +297,9 @@ impl ConflictTaskGenerator { priority: TaskPriority, ) { trace!( - "Updating tasks for group {} with priority {:?}", - group_id, - priority.display() + group = group_id, + priority = priority.display(), + "Updating tasks", ); // Cancel existing tasks for this grou self.cancel_tasks_for_group(group_id); From 7bfce1be4e0c060361cc40af407bd31fd86eb021 Mon Sep 17 00:00:00 2001 From: ZanCorDX <126988525+ZanCorDX@users.noreply.github.com> Date: Fri, 13 Dec 2024 11:44:42 -0300 Subject: [PATCH 27/30] Less warnings (#283) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 📝 Summary Less warnings ## ✅ I have completed the following steps: * [ ] Run `make lint` * [ ] Run `make test` * [ ] Added tests (if applicable) --------- Co-authored-by: Ferran Borreguero --- .../parallel_builder/conflict_resolving_pool.rs | 16 ++++++++++------ .../parallel_builder/conflict_task_generator.rs | 14 ++++---------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/crates/rbuilder/src/building/builders/parallel_builder/conflict_resolving_pool.rs b/crates/rbuilder/src/building/builders/parallel_builder/conflict_resolving_pool.rs index e9571eff..25261431 100644 --- a/crates/rbuilder/src/building/builders/parallel_builder/conflict_resolving_pool.rs +++ b/crates/rbuilder/src/building/builders/parallel_builder/conflict_resolving_pool.rs @@ -114,7 +114,7 @@ where let mut merging_context = ResolverContext::new( provider.clone(), ctx.clone(), - cancellation_token, + cancellation_token.clone(), None, simulation_cache, ); @@ -134,11 +134,15 @@ where Ok((task_id, (sequence_of_orders, task_group))) } Err(err) => { - warn!( - group_id = task_id, - err = ?err, - "Error running conflict task for group_idx", - ); + // Fast patch/heuristic to fix excessive tracing. + // TODO: Use good errors. + if !cancellation_token.is_cancelled() { + warn!( + group_id = task_id, + err = ?err, + "Error running conflict task for group_idx", + ); + } Err(err) } } diff --git a/crates/rbuilder/src/building/builders/parallel_builder/conflict_task_generator.rs b/crates/rbuilder/src/building/builders/parallel_builder/conflict_task_generator.rs index 55b2f6dd..f5919f4c 100644 --- a/crates/rbuilder/src/building/builders/parallel_builder/conflict_task_generator.rs +++ b/crates/rbuilder/src/building/builders/parallel_builder/conflict_task_generator.rs @@ -4,7 +4,7 @@ use alloy_primitives::{utils::format_ether, U256}; use crossbeam_queue::SegQueue; use itertools::Itertools; use std::time::Instant; -use tracing::{trace, warn}; +use tracing::trace; use super::{ task::ConflictTask, Algorithm, ConflictGroup, ConflictResolutionResultPerGroup, GroupId, @@ -183,16 +183,10 @@ impl ConflictTaskGenerator { total_profit: group.orders[0].sim_value.coinbase_profit, sequence_of_orders: vec![(0, group.orders[0].sim_value.coinbase_profit)], }; - if let Err(e) = self + // We ignore the error since it means "receiver disconnected" and we expect the caller will detect the cancellation and stop calling us. + let _ = self .group_result_sender - .send((group_id, (sequence_of_orders, group.clone()))) - { - warn!( - error = ?e, - group_id, - "Failed to send single order result for group", - ); - } + .send((group_id, (sequence_of_orders, group.clone()))); } /// Determines if there are any changes between a new group and an existing group. From 67df6cf48fefa35b267ee4156b37dc3ec63b367d Mon Sep 17 00:00:00 2001 From: ZanCorDX <126988525+ZanCorDX@users.noreply.github.com> Date: Fri, 13 Dec 2024 11:45:58 -0300 Subject: [PATCH 28/30] Order input traces polish (#285) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 📝 Summary - log polish - Distinguish 4484 txs wrongly encoded as canonical format as a specific error. ## 💡 Motivation and Context Trying to chase order input problems. --- ## ✅ I have completed the following steps: * [X] Run `make lint` * [X] Run `make test` * [ ] Added tests (if applicable) --- .../live_builder/order_input/rpc_server.rs | 10 ++-- crates/rbuilder/src/primitives/mod.rs | 7 ++- crates/rbuilder/src/primitives/serialize.rs | 52 ++++++++++++++++++- 3 files changed, 62 insertions(+), 7 deletions(-) diff --git a/crates/rbuilder/src/live_builder/order_input/rpc_server.rs b/crates/rbuilder/src/live_builder/order_input/rpc_server.rs index 25a1d64b..ee7dd0ea 100644 --- a/crates/rbuilder/src/live_builder/order_input/rpc_server.rs +++ b/crates/rbuilder/src/live_builder/order_input/rpc_server.rs @@ -55,7 +55,7 @@ pub async fn start_server_accepting_bundles( let bundle: Bundle = match raw_bundle.try_into(TxEncoding::WithBlobData) { Ok(bundle) => bundle, Err(err) => { - warn!(?err, "Failed to parse bundle"); + warn!(?err, "Failed to decode raw bundle"); // @Metric return; } @@ -86,7 +86,7 @@ pub async fn start_server_accepting_bundles( let raw_tx: Bytes = match params.one() { Ok(raw_tx) => raw_tx, Err(err) => { - warn!(?err, "Failed to parse transaction"); + warn!(?err, "Failed to parse raw transaction"); // @Metric return Err(err); } @@ -96,7 +96,7 @@ pub async fn start_server_accepting_bundles( let tx: MempoolTx = match raw_tx_order.decode(TxEncoding::WithBlobData) { Ok(tx) => tx, Err(err) => { - warn!(?err, "Failed to verify transaction"); + warn!(?err, "Failed to decode raw transaction"); // @Metric return Err(ErrorObject::owned(-32602, "failed to verify transaction", None::<()>)); } @@ -146,7 +146,7 @@ async fn handle_mev_send_bundle( let decode_res = match raw_bundle.decode(TxEncoding::WithBlobData) { Ok(res) => res, Err(err) => { - warn!(?err, "Failed to verify share bundle"); + warn!(?err, "Failed to decode raw share bundle"); // @Metric return; } @@ -188,7 +188,7 @@ async fn send_command( match channel.send_timeout(command, timeout).await { Ok(()) => {} Err(SendTimeoutError::Timeout(_)) => { - warn!("Failed to sent order, timout"); + warn!("Failed to sent order, timeout"); } Err(SendTimeoutError::Closed(_)) => {} }; diff --git a/crates/rbuilder/src/primitives/mod.rs b/crates/rbuilder/src/primitives/mod.rs index 32132f70..37b4e696 100644 --- a/crates/rbuilder/src/primitives/mod.rs +++ b/crates/rbuilder/src/primitives/mod.rs @@ -434,8 +434,13 @@ pub enum RawTxWithBlobsConvertError { FailedToDecodeTransaction(Eip2718Error), #[error("Invalid transaction signature")] InvalidTransactionSignature, - #[error("Invalid transaction signature")] + #[error("UnexpectedError")] UnexpectedError, + /// This error is generated when we fail (like FailedToDecodeTransaction) parsing in TxEncoding::WithBlobData mode (Network encoding) but the header looks + /// like the beginning of an ethereum mainnet Canonical encoding 4484 tx. + /// To avoid consuming resources the generation of this error might not be perfect but helps 99% of the time. + #[error("Failed to decode transaction, error: {0}. It probably is a 4484 canonical tx.")] + FailedToDecodeTransactionProbablyIs4484Canonical(alloy_rlp::Error), } impl TransactionSignedEcRecoveredWithBlobs { diff --git a/crates/rbuilder/src/primitives/serialize.rs b/crates/rbuilder/src/primitives/serialize.rs index df621965..6d324fe9 100644 --- a/crates/rbuilder/src/primitives/serialize.rs +++ b/crates/rbuilder/src/primitives/serialize.rs @@ -4,7 +4,11 @@ use super::{ ShareBundleInner, ShareBundleReplacementData, ShareBundleReplacementKey, ShareBundleTx, TransactionSignedEcRecoveredWithBlobs, TxRevertBehavior, }; +use alloy_consensus::constants::EIP4844_TX_TYPE_ID; +use alloy_eips::eip2718::Eip2718Error; use alloy_primitives::{Address, Bytes, B256, U64}; +use alloy_rlp::{Buf, Header}; +use reth_chainspec::MAINNET; use serde::{Deserialize, Deserializer, Serialize}; use serde_with::serde_as; use thiserror::Error; @@ -30,9 +34,41 @@ impl TxEncoding { TransactionSignedEcRecoveredWithBlobs::decode_enveloped_with_fake_blobs(raw_tx) } TxEncoding::WithBlobData => { - TransactionSignedEcRecoveredWithBlobs::decode_enveloped_with_real_blobs(raw_tx) + let raw_tx_clone = raw_tx.clone(); // This clone is supposed to be cheap + let res = + TransactionSignedEcRecoveredWithBlobs::decode_enveloped_with_real_blobs(raw_tx); + if let Err(RawTxWithBlobsConvertError::FailedToDecodeTransaction( + Eip2718Error::RlpError(err), + )) = res + { + if Self::looks_like_canonical_blob_tx(raw_tx_clone) { + return Err(RawTxWithBlobsConvertError::FailedToDecodeTransactionProbablyIs4484Canonical( + err, + )); + } + } + res + } + } + } + + fn looks_like_canonical_blob_tx(raw_tx: Bytes) -> bool { + // For full check we could call TransactionSigned::decode_enveloped and fully try to decode it is way more expensive. + // We expect EIP4844_TX_TYPE_ID + rlp(chainId = 01,.....) + let mut tx_slice = raw_tx.as_ref(); + if let Some(tx_type) = tx_slice.first() { + if *tx_type == EIP4844_TX_TYPE_ID { + tx_slice.advance(1); + if let Ok(outer_header) = Header::decode(&mut tx_slice) { + if outer_header.list { + if let Some(chain_id) = tx_slice.first() { + return (*chain_id as u64) == MAINNET.chain().id(); + } + } + } } } + false } } @@ -555,6 +591,7 @@ mod tests { use alloy_consensus::Transaction; use alloy_eips::eip2718::Encodable2718; use alloy_primitives::{address, fixed_bytes, keccak256, U256}; + use revm_primitives::bytes; use uuid::uuid; #[test] @@ -950,4 +987,17 @@ mod tests { serde_json::from_str(raw_tx_json).expect("failed to decode raw order with tx"); assert!(matches!(raw_order, RawOrder::Tx(_))); } + + /// We decode a 4484 Tx in canonical format using WithBlobData which is for network format. + /// We expect the specific error FailedToDecodeTransactionProbablyIs4484Canonical. + #[test] + fn test_correct_mixed_blob_mode_decoding() { + let raw_tx = bytes!("03f9021b01829f1084db518e44850efef5c902830249f09406a9ab27c7e2255df1815e6cc0168d7755feb19a80b90184648885fb000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000066cc9a0eb519e9e1de68f6cf0aa1aa1efe3723d50000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001efcf00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0843b9aca00e1a00154404fdaef0e93e6a4df6aa099f66fc4f90267b3ef5bb6ac4d3f77a456ae5180a01367ff3e4598620be9424d5be0deafe5b3d3b7221c5f5c3d9fade0f545b19890a0026cd9941cd2aa4df41d5d36aa2e82a671c3226f2924cb206363a9458f38b8f6"); + let raw_tx_order = RawTx { tx: raw_tx }; + let tx_res = raw_tx_order.decode(TxEncoding::WithBlobData); + assert!(matches!( + tx_res, + Err(RawTxWithBlobsConvertError::FailedToDecodeTransactionProbablyIs4484Canonical(_)) + )); + } } From 9835e676975a5035fe5c2df3a7e26ddcb519c5f9 Mon Sep 17 00:00:00 2001 From: ZanCorDX <126988525+ZanCorDX@users.noreply.github.com> Date: Fri, 13 Dec 2024 11:46:14 -0300 Subject: [PATCH 29/30] Builder name on errors (#286) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 📝 Summary Add builder algorithm name to 2 error! ## 💡 Motivation and Context Allows to pinpoint problems with new algorithms. --- ## ✅ I have completed the following steps: * [X] Run `make lint` * [X] Run `make test` * [ ] Added tests (if applicable) --- .../src/building/builders/block_building_helper.rs | 8 ++++++++ .../building/builders/mock_block_building_helper.rs | 4 ++++ .../block_output/bidding/parallel_sealer_bid_maker.rs | 2 ++ .../bidding/sequential_sealer_bid_maker.rs | 2 ++ crates/rbuilder/src/live_builder/mod.rs | 10 +++++++++- 5 files changed, 25 insertions(+), 1 deletion(-) diff --git a/crates/rbuilder/src/building/builders/block_building_helper.rs b/crates/rbuilder/src/building/builders/block_building_helper.rs index 5f5fbbb7..7342fdd1 100644 --- a/crates/rbuilder/src/building/builders/block_building_helper.rs +++ b/crates/rbuilder/src/building/builders/block_building_helper.rs @@ -76,6 +76,10 @@ pub trait BlockBuildingHelper: Send + Sync { /// Updates the cached reads for the block state. fn update_cached_reads(&mut self, cached_reads: CachedReads); + + /// Name of the builder that pregenerated this block. + /// BE CAREFUL: Might be ambiguous if several building parts were involved... + fn builder_name(&self) -> &str; } /// Implementation of BlockBuildingHelper based on a generic Provider @@ -422,4 +426,8 @@ where fn update_cached_reads(&mut self, cached_reads: CachedReads) { self.block_state = self.block_state.clone().with_cached_reads(cached_reads); } + + fn builder_name(&self) -> &str { + &self.builder_name + } } diff --git a/crates/rbuilder/src/building/builders/mock_block_building_helper.rs b/crates/rbuilder/src/building/builders/mock_block_building_helper.rs index f55f1889..26d38112 100644 --- a/crates/rbuilder/src/building/builders/mock_block_building_helper.rs +++ b/crates/rbuilder/src/building/builders/mock_block_building_helper.rs @@ -105,4 +105,8 @@ impl BlockBuildingHelper for MockBlockBuildingHelper { fn update_cached_reads(&mut self, _cached_reads: CachedReads) { unimplemented!() } + + fn builder_name(&self) -> &str { + "Mock" + } } diff --git a/crates/rbuilder/src/live_builder/block_output/bidding/parallel_sealer_bid_maker.rs b/crates/rbuilder/src/live_builder/block_output/bidding/parallel_sealer_bid_maker.rs index 4f3d4eeb..2863e718 100644 --- a/crates/rbuilder/src/live_builder/block_output/bidding/parallel_sealer_bid_maker.rs +++ b/crates/rbuilder/src/live_builder/block_output/bidding/parallel_sealer_bid_maker.rs @@ -121,6 +121,7 @@ impl ParallelSealerBidMakerProcess { let payout_tx_val = bid.payout_tx_value(); let block = bid.block(); let block_number = block.building_context().block(); + let builder_name = block.builder_name().to_string(); // Take sealing "slot" *self.seal_control.seals_in_progress.lock() += 1; let seal_control = self.seal_control.clone(); @@ -129,6 +130,7 @@ impl ParallelSealerBidMakerProcess { match block.finalize_block(payout_tx_val) { Ok(res) => sink.new_block(res.block), Err(error) => error!( + builder_name, block_number, ?error, "Error on finalize_block on ParallelSealerBidMaker" diff --git a/crates/rbuilder/src/live_builder/block_output/bidding/sequential_sealer_bid_maker.rs b/crates/rbuilder/src/live_builder/block_output/bidding/sequential_sealer_bid_maker.rs index 708a2be3..c41d3b4b 100644 --- a/crates/rbuilder/src/live_builder/block_output/bidding/sequential_sealer_bid_maker.rs +++ b/crates/rbuilder/src/live_builder/block_output/bidding/sequential_sealer_bid_maker.rs @@ -90,12 +90,14 @@ impl SequentialSealerBidMakerProcess { let payout_tx_val = bid.payout_tx_value(); let block = bid.block(); let block_number = block.building_context().block(); + let builder_name = block.builder_name().to_string(); match tokio::task::spawn_blocking(move || block.finalize_block(payout_tx_val)).await { Ok(finalize_res) => match finalize_res { Ok(res) => self.sink.new_block(res.block), Err(error) => { if error.is_critical() { error!( + builder_name, block_number, ?error, "Error on finalize_block on SequentialSealerBidMaker" diff --git a/crates/rbuilder/src/live_builder/mod.rs b/crates/rbuilder/src/live_builder/mod.rs index abdbd973..d4110fe8 100644 --- a/crates/rbuilder/src/live_builder/mod.rs +++ b/crates/rbuilder/src/live_builder/mod.rs @@ -131,6 +131,8 @@ where } pub async fn run(self) -> eyre::Result<()> { + // We keep the last block to avoid going back in time since we are now very robust about reorgs or this kind of behavior. + let mut last_processed_block: Option = None; info!("Builder block list size: {}", self.blocklist.len(),); info!( "Builder coinbase address: {:?}", @@ -195,8 +197,13 @@ where ); continue; } + // Allow only increasing blocks + if last_processed_block.map_or(false, |last_processed_block| { + payload.block() <= last_processed_block + }) { + continue; + } // see if we can get parent header in a reasonable time - let time_to_slot = payload.timestamp() - OffsetDateTime::now_utc(); debug!( slot = payload.slot(), @@ -235,6 +242,7 @@ where ); inc_active_slots(); + last_processed_block = Some(payload.block()); if let Some(block_ctx) = BlockBuildingContext::from_attributes( payload.payload_attributes_event.clone(), From 171d8fcb2de834b6d46463979f8643756c599e86 Mon Sep 17 00:00:00 2001 From: ZanCorDX <126988525+ZanCorDX@users.noreply.github.com> Date: Fri, 13 Dec 2024 14:29:28 -0300 Subject: [PATCH 30/30] Better logs. (#287) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit slot timings ## 📝 Summary - Timing info about "Received payload" - Watchdog kill reason. ## 💡 Motivation and Context Help problem identification on prod. ## ✅ I have completed the following steps: * [X] Run `make lint` * [X] Run `make test` * [ ] Added tests (if applicable) --- crates/rbuilder/src/live_builder/mod.rs | 10 ++++++++-- crates/rbuilder/src/live_builder/watchdog.rs | 10 +++++++--- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/crates/rbuilder/src/live_builder/mod.rs b/crates/rbuilder/src/live_builder/mod.rs index d4110fe8..5b7c78e2 100644 --- a/crates/rbuilder/src/live_builder/mod.rs +++ b/crates/rbuilder/src/live_builder/mod.rs @@ -181,7 +181,10 @@ where ); let watchdog_sender = match self.watchdog_timeout { - Some(duration) => Some(spawn_watchdog_thread(duration)?), + Some(duration) => Some(spawn_watchdog_thread( + duration, + "block build started".to_string(), + )?), None => { info!("Watchdog not enabled"); None @@ -203,11 +206,14 @@ where }) { continue; } + let current_time = OffsetDateTime::now_utc(); // see if we can get parent header in a reasonable time - let time_to_slot = payload.timestamp() - OffsetDateTime::now_utc(); + let time_to_slot = payload.timestamp() - current_time; debug!( slot = payload.slot(), block = payload.block(), + ?current_time, + payload_timestamp = ?payload.timestamp(), ?time_to_slot, "Received payload, time till slot timestamp", ); diff --git a/crates/rbuilder/src/live_builder/watchdog.rs b/crates/rbuilder/src/live_builder/watchdog.rs index 1dd95d3f..3d91eb49 100644 --- a/crates/rbuilder/src/live_builder/watchdog.rs +++ b/crates/rbuilder/src/live_builder/watchdog.rs @@ -4,7 +4,8 @@ use tracing::{error, info}; /// Spawns a thread that will kill the process if there is no events sent on the channel /// for the timeout time. -pub fn spawn_watchdog_thread(timeout: Duration) -> io::Result> { +/// context is a string to be logged to be able to distinguish different types of deaths. +pub fn spawn_watchdog_thread(timeout: Duration, context: String) -> io::Result> { let (sender, receiver) = flume::unbounded(); std::thread::Builder::new() .name(String::from("watchdog")) @@ -13,7 +14,7 @@ pub fn spawn_watchdog_thread(timeout: Duration) -> io::Result> match receiver.recv_timeout(timeout) { Ok(()) => {} Err(RecvTimeoutError::Timeout) => { - error!("Watchdog timeout"); + error!(context, "Watchdog timeout"); std::process::exit(1); } Err(RecvTimeoutError::Disconnected) => { @@ -21,7 +22,10 @@ pub fn spawn_watchdog_thread(timeout: Duration) -> io::Result> } } } - info!("Watchdog finished, will kill application in 12 seconds"); + info!( + context, + "Watchdog finished, will kill application in 12 seconds" + ); std::thread::sleep(Duration::from_secs(12)); std::process::exit(1);